簡體   English   中英

我能否以某種方式評估表達式以確定並可能設置null屬性?

[英]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();

我認為你可以使用ExpandoObjectElasticObject

據我所知,ExpandoObject將被“轉換”為字典(Properties => Values)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM