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.两者之间的性能差异会很大. 当然,请记住,为了提高性能,我们正在进入更复杂,更难阅读的高级代码区域.您可以认为这种过度优化和过度杀害非性能关键的代码. 但在我写的代码中,我避免像瘟疫那样的反思. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |