2017-12-11 13 views
0

リフレクションを使用して構造体のすべての部分のMemberExpressionを決定しようとしています。私はすべてのコンポーネントのMemberExpressionを決定するために使用さリフレクションと継承の問題C#

public class Entity 
{ 
    public Part FirstPart { get; set; } 
} 

public class Part 
{ 
    public int Id { get; set; } 
} 

public class SubPart : Part 
{ 
    public int ExtraProperty { get; set; } 
} 

機能、次のオブジェクト構造のために正常に動作します:これらの問題を説明するために、オブジェクトの一部です

 Entity entity = new Entity() { FirstPart = new Part() { Id = 1 } }; 

機能は次のとおりです。

 var param = Expression.Parameter(entity.GetType()); 
     String[] childProperties = ("FirstPart.Id").Split('.'); 
     var propExpression = Expression.PropertyOrField(param, childProperties[0]); 
     for (int i = 1; i < childProperties.Length; i++) 
     { 
      propExpression = Expression.PropertyOrField(propExpression, childProperties[i]); 
     } 

しかし、これが原因継承するには、次のようには機能しません:

 Entity entity = new Entity() { FirstPart = new SubPart() { ExtraProperty = 1 } }; 

私たちは「FirstPart.ExtraProperty」へのパスを変更する必要があるプロパティをたどるために:「ExtraPropertyは」パートのメンバーではありません。

 var param = Expression.Parameter(entity.GetType()); 
     String[] childProperties = ("FirstPart.ExtraProperty").Split('.'); 
     var propExpression = Expression.PropertyOrField(param, childProperties[0]); 
     for (int i = 1; i < childProperties.Length; i++) 
     { 
      propExpression = Expression.PropertyOrField(propExpression, childProperties[i]); 
     } 

エラーメッセージがあると述べています。誰もがこの問題を克服する方法を知っていますか?

+1

キャストする必要があります。 – SLaks

+1

これについて考えると、 'entity.FirstPart.ExtraProperty = 5;'を実行することができませんでした。なぜなら、式は異なるものではありません。 – DavidG

+0

返信いただきありがとうございます。鋳造プロセスの例を説明できますか? –

答えて

3

できません。式はコンパイル時ではなく実行時にコンパイルされるコードと考えることができます。魔法はなく、同様の規則が適用されます(式は低レベルで制限が厳しいため、C#コードレベルで利用可能な構文砂糖の多くは式では使用できません)。つまり、entity.FirstPart.ExtraPropertyはC#コードでは有効ではないため、式でも有効ではありません。

あなたは明示的なキャストを挿入することができます - しかし、あなたはそのインスタンスが実際にタイプSubPartのものであろうと仮定し、なぜあなたは代わりにPartのタイプSubPartのメンバーFirstPartを定義しません。または、TypeIs expressionを使用して型テストロジックを作成し、C#コードと同じ方法でキャストできます。

EDIT:

あなたの問題を再読み込みした後、私はあなたが実際に実装しようとしているが、任意のオブジェクトの上にプロパティ歩行器であることがわかります。だから、TypeIs式はコンパイル時にテストされている型が分かっているので、ここで助けにならないでしょう。しかし、あなたのケースでは、から派生した任意のクラスが任意の追加プロパティーを持つFirstPartメンバーにある可能性があります。この場合、他のオプションはありませんが、各プロパティへのアクセスを1つずつ評価し、実際のタイプを中間値から取得します。例:

Entity entity = new Entity() { FirstPart = new SubPart() { ExtraProperty = 1 } }; 

object currentObjectInChain = entity; 
String[] childProperties = ("FirstPart.ExtraProperty").Split('.'); 

foreach (var property in childProperties) 
{ 
    if (currentObjectInChain == null) 
    { 
     throw new ArgumentException("Current value is null"); 
    } 
    var type = currentObjectInChain.GetType(); 
    var param = Expression.Parameter(type); 
    var lambda = Expression.Lambda(
     Expression.PropertyOrField(param, property), 
     param).Compile(); // cache based on type and property name 
    currentObjectInChain = lambda.DynamicInvoke(currentObjectInChain); 
} 

ループの最後に、あなたの価値が保持されます。

+0

同じ基本クラスの他のサブクラスもあると仮定する必要があるため、Partの代わりにFirstPartメンバをSubPartとして定義するだけでは問題ありません。私はTypeIsを知らないし、このケースでどのようにキャストすることができないのか分からない、例を詳しく教えてもらえますか?事前に感謝 –

+0

ちょうど私が探していた、感謝:) –