【问题标题】:C#: Func with a constructor of an inherited typeC#:具有继承类型的构造函数的函数
【发布时间】:2011-05-30 13:58:21
【问题描述】:

据我们所知,您可以像这样将构造函数指向 Func<T>

Func<MyObject> constructor = () => new MyObject();
var newObject = constructor();

但是有没有办法让一个你知道继承自 MyObject 的对象的构造函数,但你不知道它的确切类型?

Type inheritedObjectType = obj; // Parameter
Func<MyObject> constructor = () => new MyObject(); // as inheritedObjectType
var newInheritedObject = constructor; // Should now be of the inherited type

不能选择使用Activator 或任何返回Object 的答案。

编辑:我不知道在编译时派生类型是什么类型。我只有一个System.Type

【问题讨论】:

    标签: c# lambda constructor func inherited


    【解决方案1】:

    您可以使用表达式树来构建和编译将创建派生类型的委托:

    Func<TBase> CreateDelegate<TBase>(Type derived)
    {
        var ctor = derived.GetConstructor(Type.EmptyTypes);
    
        if (ctor == null)
        {
            throw new ArgumentException("D'oh! No default ctor.");
        }
    
        var newExpression = Expression.Lambda<Func<TBase>>(
            Expression.New(ctor, new Expression[0]), 
            new ParameterExpression[0]);
    
        return newExpression.Compile();
    }
    

    你可以简单地这样称呼它:

    Func<MyBase> create = CreateDelegate<MyBase>(typeof(Derived));
    
    MyBase instance = create();
    

    当您缓存该委托时,您将获得最佳性能。

    【讨论】:

    • 顺便说一句:这正是依赖注入框架将为您做的事情。大多数框架将允许注册如下语法:container.Register(typeof(MyBase), derived),您可以获得一个新实例,如下所示:container.GetInstance&lt;MyBase&gt;() et voila。
    【解决方案2】:

    这个程序是否表现出预期的行为?

    class MyObject{}
    class Derived : MyObject {}
    internal class Program
    {
    
        public static void Main()
        {
            // the type you want to construct
            Type type = typeof (Derived);
    
            MethodInfo getConstructor = MakeConstructorGetter(type);
            Func<MyObject> constructor = (Func<MyObject>)getConstructor.Invoke(null, null);
    
            var obj = constructor();
            Console.WriteLine(obj.GetType());
        }
    
        private static MethodInfo MakeConstructorGetter(Type type)
        {
            MethodInfo mi = typeof(Program).GetMethod("GetObjectConstructor", BindingFlags.Static | BindingFlags.NonPublic);
            var getConstructor = mi.MakeGenericMethod(type);
            return getConstructor;
        }
    
        private static Func<T> GetObjectConstructor<T>() where T : MyObject, new()
        {
            return () => new T();
        }
    }
    

    如果Type 描述的类型与通用约束不匹配,MakeConstructorGetter 将抛出异常。因此,这将在执行时间而不是在编译期间失败,但我想这是在像这样动态处理泛型时需要做出的权衡。

    【讨论】:

    • 除了 System.Type,我不知道“派生”是什么。
    • @Seb:更新了答案,以便为给定的Type 构造一个通用方法。
    • 嗯,“getConstructor.Invoke”基本上类似于Activator.CreateInstance,返回一个Object。我想引用构造函数 lambda 以提高性能,而基于反射的等效项并不完全具备。如果做不到,那就是正确的答案,你的解决方案是最接近的。
    • @Seb:注意getConstructor.Invoke返回通用构造函数但不构造对象;该对象是由构造的通用调用创建的(因此那里不应该有反射)。您应该能够轻松地缓存每种类型生成的构造函数。
    • 这真的有效吗?我认为getConstructor.Invoke(null, null) 不会返回Func&lt;T&gt;,而只是从MyObject 继承的东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-17
    • 1970-01-01
    • 1970-01-01
    • 2017-03-11
    • 1970-01-01
    • 1970-01-01
    • 2013-01-24
    相关资源
    最近更新 更多