Expressions
実際には同じではありませんが、そうでなければなりません。彼らは少し細部に違いがあります。私はExpressions
にはかなり新しいですが、これはかなり経験豊富なプレイヤーにとっても混乱を招く可能性があると思います。私はIQueryable.Where()
のパラメータとしてExpression
を使用するようにいくつかのデータを処理するコードをリファクタリングしました。私が見る限り、それは機能的に同等です。式はほぼ同じですが、そのうちの1つが動作していません
私はここでうまく働いた元のコードを、持っている、と完全に機能的な表現を生成します。
private Expression<Func<T, bool>> StringPropertyContains<T>(string propertyName, string value)
{
if (string.IsNullOrWhiteSpace(propertyName))
{
throw new ArgumentNullException(nameof(propertyName));
}
var param = Expression.Parameter(typeof(T));
MemberExpression member = null;
if (propertyName.Contains('/'))
{
var splittedPropertyName = propertyName.Split('/');
var propertyInfo = this.GetPropertyInfo(typeof(T), splittedPropertyName.First());
member = Expression.MakeMemberAccess(param, propertyInfo);
for (int i = 1; i < splittedPropertyName.Length; i++)
{
if (propertyInfo.PropertyType.IsInterface)
{
//specifically for IActorWithExtraDetails -> reason to refactor
if (typeof(IActor).IsAssignableFrom(propertyInfo.PropertyType) && typeof(IActor).GetProperties().FirstOrDefault(pi => pi.Name.Equals(splittedPropertyName[i], StringComparison.OrdinalIgnoreCase)) != null)
{
propertyInfo = this.GetPropertyInfo(typeof(IActor), splittedPropertyName[i]);
}
else
{
propertyInfo = this.GetPropertyInfo(propertyInfo.PropertyType, splittedPropertyName[i]);
}
}
else
{
propertyInfo = this.GetPropertyInfo(propertyInfo.PropertyType, splittedPropertyName[i]);
}
}
member = Expression.MakeMemberAccess(member, propertyInfo);
}
else
{
var propertyInfo = this.GetPropertyInfo(typeof(T), propertyName);
member = Expression.MakeMemberAccess(param, propertyInfo);
}
var constant = Expression.Constant(value, typeof(string));
var methodInfo = typeof(string).GetMethod("Contains", new Type[] { typeof(string) });
var body = Expression.Call(member, methodInfo, constant);
return Expression.Lambda<Func<T, bool>>(body, param);
}
は、これはIQueryable
のDebugView
プロパティにどのように見えるかです:ここでは
.Lambda #Lambda2<System.Func`2[AccessManagement.Model.Application,System.Boolean]>(AccessManagement.Model.Application $var1)
{
.Call ($var1.Name).Contains("hive")
}
は、新しいですリファクタリングされたコードを独自のメソッドに移動:
これは、リファクタリングメソッドからの発現がDebugView
でどのように見えるかです:
.Lambda #Lambda2<System.Func`2[AccessManagement.Model.Application,System.Boolean]>(AccessManagement.Model.Application $var1)
{
.Call ($var2.Name).Contains("hive")
}
一つだけ違いがあります。ご覧のとおり、$var2
があります。$var1
ではありません。この変数は、式ツリー全体には存在しません。理由は分かりませんが、他のすべてが同じなので、それが問題だと思います。他の違いは、Expression
の処理がmember.RuntimeMethodInfo.base.m_cachedData
(デバッグビューのパス)にキャッチされている場合です。あなたの最初のコードスニペットで
最初のコードスニペットは 'param'式を使用し、2番目のコードスニペットはそれを無視します。 –
@LucasTrzesniewski申し訳ありません!ひどい間違い、私はリファクタリングされた式の処理を追加するのを忘れていましたが、 'param'は2番目のスニペットの最初のメソッドの最後の行に使われています – Qerts
私が言ったことを誤解していると思います:)このコードを見てください' Expression.MakeMemberAccess Expression.Parameter(baseType)、propertyInfo) 'のように、' Expression.Parameter(baseType) 'を' param'への参照で置き換えます。これは 'Expression.Lambda'に渡すものと同じものです。ここでは第2の無関係のパラメータを作成しています。これは '$ var2'の由来です。 –