[英]Can I evaluate an expression in a way to determine and possibly set a property that is null?
我有一個服務,它接受一個對象,並根據其中的屬性將執行不同的操作; 使用此任何這些屬性都可以為null,這意味着不執行此操作。
我正在嘗試創建一個非常簡單的API,以便在某些屬性可以是多個級別的情況下執行此操作,這是當前實現的示例
service.PerformActions(DataFactory.GetNewData<ActionsInfo> (
data => data.SomeParent = DataFactory.GetNewData<SomeParentInfo>(),
data => data.SomeParent.SomeProperty = "someValue" ));
這是一個略微簡化的版本,在實際情況下,我有時必須以這種方式設置多個父屬性,以便在底部設置一個字符串屬性。
我想要做的是調整GetNewData方法中的代碼來處理根據需要實例化這些屬性,以便代碼看起來像這樣:
service.PerformActions(DataFactory.GetNewData<ActionsInfo> (
data => data.SomeParent.SomeProperty = "someValue" ));
這是我目前的GetNewData代碼:
public static T GetNewData<T>(params Action<T>[] actions)
{
var data = Activator.CreateInstance<T>();
foreach (var action in actions)
{
try
{
action(data);
}
catch (NullReferenceException)
{
throw new Exception("The property you are attempting to set is within a property that has not been set.");
}
}
return data;
}
我的第一個想法是將params
數組更改為Expression<Action<T>>[]
操作,並以某種方式獲取任何這些null的父項的成員表達式,這將允許我使用激活器來創建實例。 然而,我對表達樹更高級功能的體驗至多是微不足道的。
試圖使這個API盡可能簡單化的原因是它是一個最終將由非開發人員使用的UI測試框架。
編輯:我想添加一個當前實現的另一個例子,希望能夠證明我正在嘗試做的事情將提供更易讀的代碼,是的,如果我可以解決這個問題,那么會產生非常輕微的“副作用”但是我我認為這是一個有用的。
ExampleDataFactory.GetNewData<ServicesAndFeaturesInfo>(
x => x.Property1 = ExampleDataFactory.GetNewData<Property1Type>(),
x => x.Property1.Property2 = ExampleDataFactory.GetNewData<Property2Type>(),
x => x.Property1.Property2.Property3 = ExampleDataFactory.GetNewData<Property3Type>(),
x => x.Property1.Property2.Property3.Property4 = true);
編輯2:我在這里使用的類是從Apache Thrift結構定義生成的,因此我無法控制它們以便能夠設置某種智能構造函數。
在得到我的另一個問題的答案之后,我現在有一個完全可行的解決方案,它不像我最初的目標那樣簡單,但它並不壞。
public static DataBuilder<T> GetNewData<T>() where T : class, new()
{
return new DataBuilder<T>();
}
DataBuilder類:
public class DataBuilder<T>
{
public readonly T data;
public DataBuilder()
{
data = Activator.CreateInstance<T>();
}
public DataBuilder(T data)
{
this.data = data;
}
public DataBuilder<T> SetValue<T2>(Expression<Func<T, T2>> expression, T2 value)
{
var mExpr = GetMemberExpression(expression);
var obj = Recurse(mExpr);
var p = (PropertyInfo)mExpr.Member;
p.SetValue(obj, value);
return this;
}
public T Build()
{
return data;
}
public object Recurse(MemberExpression expr)
{
if (expr.Expression.Type != typeof(T))
{
var pExpr = GetMemberExpression(expr.Expression);
var parent = Recurse(pExpr);
var pInfo = (PropertyInfo) pExpr.Member;
var obj = pInfo.GetValue(parent);
if (obj == null)
{
obj = Activator.CreateInstance(pInfo.PropertyType);
pInfo.SetValue(parent, obj);
}
return obj;
}
return data;
}
private static MemberExpression GetMemberExpression(Expression expr)
{
var member = expr as MemberExpression;
var unary = expr as UnaryExpression;
return member ?? (unary != null ? unary.Operand as MemberExpression : null);
}
private static MemberExpression GetMemberExpression<T2>(Expression<Func<T, T2>> expr)
{
return GetMemberExpression(expr.Body);
}
}
用法:
ExampleDataFactory.GetNewData<ServicesAndFeaturesInfo>()
.SetValue(x=> x.Property1.EnumProperty, EnumType.Own)
.SetValue(x=> x.Property2.Property3.Property4.BoolProperty, true)
.Build();
我認為你可以使用ExpandoObject或ElasticObject 。
據我所知,ExpandoObject將被“轉換”為字典(Properties => Values)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.