加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 用反射实例化不可变对象

发布时间:2020-12-15 05:41:03 所属栏目:百科 来源:网络整理
导读:我创建了一个基类来帮助我减少C#中不可变对象初始化的样板代码, 我正在使用延迟初始化,以尽量不影响性能, 我想知道这样做对我的影响有多大? 这是我的基类: public class ImmutableObjectT{ private readonly FuncIEnumerableKeyValuePairstring,object ini
我创建了一个基类来帮助我减少C#中不可变对象初始化的样板代码,

我正在使用延迟初始化,以尽量不影响性能,
我想知道这样做对我的影响有多大?

这是我的基类:

public class ImmutableObject<T>
{
    private readonly Func<IEnumerable<KeyValuePair<string,object>>> initContainer;

    protected ImmutableObject() {}

    protected ImmutableObject(IEnumerable<KeyValuePair<string,object>> properties)
    {
        var fields = GetType().GetFields().Where(f=> f.IsPublic);

        var fieldsAndValues =
            from fieldInfo in fields
            join keyValuePair in properties on fieldInfo.Name.ToLower() equals keyValuePair.Key.ToLower()
            select new  {fieldInfo,keyValuePair.Value};

        fieldsAndValues.ToList().ForEach(fv=> fv.fieldInfo.SetValue(this,fv.Value));

    }

    protected ImmutableObject(Func<IEnumerable<KeyValuePair<string,object>>> init)
    {
        initContainer = init;
    }

    protected T setProperty(string propertyName,object propertyValue,bool lazy = true)
    {

        Func<IEnumerable<KeyValuePair<string,object>>> mergeFunc = delegate
                                                                        {
                                                                            var propertyDict = initContainer == null ? ObjectToDictonary () : initContainer();
                                                                            return propertyDict.Select(p => p.Key == propertyName? new KeyValuePair<string,object>(propertyName,propertyValue) : p).ToList();
                                                                        };

        var containerConstructor = typeof(T).GetConstructors()
            .First( ce => ce.GetParameters().Count() == 1 && ce.GetParameters()[0].ParameterType.Name == "Func`1");

        return (T) (lazy ?  containerConstructor.Invoke(new[] {mergeFunc}) :  DictonaryToObject<T>(mergeFunc()));
    }

    private IEnumerable<KeyValuePair<string,object>> ObjectToDictonary()
    {
        var fields = GetType().GetFields().Where(f=> f.IsPublic);
        return fields.Select(f=> new KeyValuePair<string,object>(f.Name,f.GetValue(this))).ToList();
    }

    private static object DictonaryToObject<T>(IEnumerable<KeyValuePair<string,object>> objectProperties)
    {
        var mainConstructor = typeof (T).GetConstructors()
            .First(c => c.GetParameters().Count()== 1 && c.GetParameters().Any(p => p.ParameterType.Name == "IEnumerable`1") );
        return mainConstructor.Invoke(new[]{objectProperties});
    }

    public T ToObject()
    {
        var properties = initContainer == null ? ObjectToDictonary() : initContainer();
        return (T) DictonaryToObject<T>(properties);
    }
}

可以像这样实现:

public class State:ImmutableObject<State>
{
    public State(){}
    public State(IEnumerable<KeyValuePair<string,object>> properties):base(properties) {}
    public State(Func<IEnumerable<KeyValuePair<string,object>>> func):base(func) {}

    public readonly int SomeInt;
    public State someInt(int someInt)
    {
        return setProperty("SomeInt",someInt);
    }

    public readonly string SomeString;
    public State someString(string someString)
    {
        return setProperty("SomeString",someString);
    }
}

并可以像这样使用:

//creating new empty object
var state = new State();

// Set fields,will return an empty object with the "chained methods".
var s2 = state.someInt(3).someString("a string");
// Resolves all the "chained methods" and initialize the object setting all the fields by reflection.
var s3 = s2.ToObject();

解决方法

那么回答你关于性能的问题,反思非常昂贵(相对而言).如果它是性能关键代码,我不会使用你的设计.

在泛型和反射方面,性能影响通常会非常大.考虑一下这么简单的事情:

public class Builder<T> where T : new()
{
    public T Build()
    {
        return new T();
    }
}

这实际上做的是调用Activator.CreateInstance,它使用反射,而且非常昂贵.

如果我想像上面的情况那样优化代码,我会使用dynamic methods.两者之间的性能差异会很大.

当然,请记住,为了提高性能,我们正在进入更复杂,更难阅读的高级代码区域.您可以认为这种过度优化和过度杀害非性能关键的代码.

但在我写的代码中,我避免像瘟疫那样的反思.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读