我正試圖建立一個流體API來通過表達式樹來設置對象的屬性值。而做到這一點:C#表達式樹:將實體參數投射到接口
public static class Converters
{
public static SomeType ToSomeType(this Dictionary<string, string> values, string fieldName)
{
//...conversion logic
}
}
public class Target : ITarget
{
public SomeType Prop1 {get; set;}
public void SetValues(Dictionary<string, string> values)
{
Prop1 = values.ToSomeType("fieldName");
}
}
我希望能夠做到這一點:
public class Target : ITarget
{
public Target()
{
this.SetProperty(x=>x.Prop1, y => y.ToSomeType("fieldName"));
}
public void SetValues(Dictionary<string, string> values)
{
//...logic that executes compiled converter functions derived from
// SetProperty calls, and which are stored in an internal list
}
}
我做了對的SetProperty靜態方法取得了一些進展,把我遇到的一個問題在這裏我需要指向同一個對象作爲一個特定的類(目標,在我的例子)的兩個實例,並作爲ITarget:在執行的SetProperty的最後一行出現
public static void SetProperty<TEntity, TProperty>(this TEntity target, Expression<Func<TEntity, object>> memberLambda,
Expression<Func<IImportFile, TProperty>> converter)
where TEntity: class, ITarget
{
var memberSelector = memberLambda.Body as MemberExpression;
if(memberSelector == null)
throw new ArgumentException(
$"{nameof(SetProperty)} -- invalid property specification on Type {typeof(TEntity).FullName}");
var propInfo = memberSelector.Member as PropertyInfo;
if(propInfo == null)
throw new ArgumentException(
$"{nameof(SetProperty)} -- invalid property specification on Type {typeof(TEntity).FullName}");
MethodCallExpression convMethod = converter.Body as MethodCallExpression;
if(convMethod == null)
throw new ArgumentException(
$"{nameof(SetProperty)} -- converter does not contain a MethodCallExpression on Type {typeof(IImportFile).FullName}");
ParameterExpression targetExp = Expression.Parameter(typeof(TEntity), "target");
MemberExpression propExp = Expression.Property(targetExp, propInfo);
BinaryExpression assignExp = Expression.Assign(propExp, convMethod);
// this next line throws the exception
var junk = Expression.Lambda<Action<ITarget, IImportFile>>(assignExp, targetExp,
(ParameterExpression) convMethod.Arguments[ 0 ]).Compile();
}
的問題。編譯器不會接受第二個參數 - 從convMethod的參數派生的參數 - 因爲就它而言,TEntity!= ITarget。
當然,除了我的示例中的TEntity - Target,它被定義爲實現ITarget :)。
我認爲表達式編譯代碼正在做什麼真正嚴格的類型檢查,而不是看一個參數是否代表可以轉換成需要的東西。
但我不知道如何將ParameterExpression轉換爲不同的類型,同時仍然指向相同的參數。我嘗試了Expression.Convert(),但這不起作用,因爲它返回一個UnaryExpression,Expression.Lambda調用不會將其作爲ParameterExpression。
跟進#1
我糾正了參考IImportTarget,是ITarget。對此感到抱歉。
我沒有解釋這是整個系統的一部分,因爲它是相當大的,具體的問題 - 你如何有兩個ParameterExpressions引用同一個對象,但是是不同的類型(它們通過一個公共接口) - 是應該在很多地方出現的東西。
這裏是確切的異常信息:出現
System.ArgumentException的HResult = -2147024809
消息=不能用於類型的代表參數類型的ParameterExpression 'ConsoleApp1.TestTarget' 「ImportFramework.IImportTarget 「
源= System.Core程序堆棧跟蹤: 在System.Linq.Expressions.Expression.ValidateLambdaArgs(類型delegateType,表達&體,ReadOnlyCollection1 parameters) at System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, String name, Boolean tailCall, IEnumerable
1個參數) 在System.Linq.Expression s .Expression.Lambda [TDelegate](表達式正文, Boolean tailCall,IEnumerable1 parameters) at ImportFramework.ImportAgentExtensions.SetProperty[TEntity,TProperty](TEntity target, Expression
1 memberLambda,Expression`1 converter)in C:\ Programming \ ConnellCampaigns \ src \ ImportFramework \ ImportAgent。CS:行 55的InnerException:
有什麼機會可以說出確切的錯誤是什麼?我也看不到你想要你的代碼做什麼。你想將任何字符串值轉換爲任何類型的對象?當時不會有更好的物體嗎?你在哪裏定義了'IImportTarget',因爲它看起來並不真正看到'ITarget'被鏈接到它,但這可能是因爲你的示例是不完整的(它也不是where子句的一部分) – Icepickle
請見後續#1 –