リフレクションを使用して、構造体のすべての部分のMemberExpressionを決定しようとしています。これらは、問題を説明するためのオブジェクトの一部です。
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; }
}
すべてのコンポーネントのMemberExpressionを決定するために使用した関数は、次のオブジェクト構造で正常に機能します。
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」に変更する必要があります。
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]);
}
エラーメッセージには、次のように記載されています。'ExtraProperty 'はPartのメンバーではありません。誰かがこの問題を克服する方法を知っていますか?
できません。式は、コンパイル時ではなく実行時にコンパイルされるコードと考えてください。魔法はなく、同様のルールが適用されます(式は低レベルで制限が厳しいため、C#コードレベルで使用できる多くのシンタックスシュガーは式では使用できません)。つまり、entity.FirstPart.ExtraProperty
C#コードでは無効であるため、式でも有効ではありません。
明示的なキャストを挿入することもできますが、インスタンスは実際には型SubPart
であると想定しているので、の代わりにFirstPart
型のメンバーを定義してみませんか。または、TypeIs式を使用して型テストロジックを作成し、C#コードの場合と同じ方法でキャストすることもできます。SubPart
Part
編集:
問題を読み直したところ、実際に実装しようとしているのは、任意のオブジェクトに対するプロパティウォーカーであることがわかりました。したがって、TypeIs
式は、テスト対象の型がコンパイル時に認識されている必要があるため、ここでは役に立ちません。しかし、あなたの場合、任意の追加プロパティを持つPart
inFirstPart
メンバーから派生した任意のクラスが存在する可能性があります。この場合、他のオプションはありませんが、各プロパティアクセスを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);
}
ループの終わりにcurrentObjectInChain
あなたの値を保持します。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加