从Type获取新的对象实例

在编译时,人们可能并不总是知道对象的类型,但可能需要创建一个类型的实例。你如何从Type获得一个新的对象实例?

0
额外 编辑
意见: 1
你在谈论ArcGIS 10中的基础层吗?
额外 作者 Devdatta Tengshe,
我认为他正在谈论使用BaseCustomLayer类实现自定义图层。
额外 作者 Reed Copsey,

13 答案

您是否尝试从 BaseCustomGlobeLayer 而不是?

Update: I just tried that and it doesn't work. I then derived from BaseCustomLayer then implemented IGraphicsContainer3D and was able to add it to the scene without getting an error.

2
额外
在这里创建后续问题中的接口
额外 作者 saint_groceon,
查看实现ILayerEvents 它们看起来都是作为出站接口(globe和3D图层除外)。一个很好的问题是:如何在C#中为自定义类实现多个出站接口?
额外 作者 saint_groceon,
我认为这是另一个与缺少出站接口有关的问题。在弧形贴图中, featurelayer coclass 实现ILayerEvents作为出站接口。我怀疑graphicslayer3d的文档a>是不正确的,并且ILayerEvents应该是出站的,因为它是用于featurelayer coclass的。
额外 作者 saint_groceon,
@ReedCopsey查看 OMD 我看到GraphicsLayer3D实现IActiveViewEvents作为出站接口。我怀疑项目已删除需要在图形移除时触发。
额外 作者 saint_groceon,
我不确定,直到我尝试。你是对的 - 它不适用于ArcScene。
额外 作者 saint_groceon,
IGraphicsContainer3D似乎是关键。谢谢!
额外 作者 Thejesh GN,
这不仅适用于ArcGlobe吗?它也可以在ArcScene中工作吗?
额外 作者 Reed Copsey,
@DBaker你最终得到了这个工作吗?我已经尝试过了,虽然它没有错误地添加,但行为并不是“干净”的(即:IGraphicsContainer3D的图形将永远不会移除,等等)......
额外 作者 Reed Copsey,
@KirkKuykendall我只是实现了整个IActiveViewEvents(和ILayerEvents),仍然得到相同的奇怪行为...
额外 作者 Reed Copsey,
这并不是说我要移除图​​形 - 即使将图层可见性设置为false也不会导致项目清除。
额外 作者 Reed Copsey,

此问题的一个实现是尝试调用Type的无参数构造函数:

public static object GetNewObject(Type t)
{
    try
    {
        return t.GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return null;
    }
}

这是同样的方法,包含在一个通用的方法中:

public static T GetNewObject()
{
    try
    {
        return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return default(T);
    }
}
0
额外
异常驱动编程?这似乎是一个非常糟糕的实现,当你可以简单地反思类型来确定构造函数。
额外 作者 Firoso,

System 命名空间中的 Activator 类非常强大。

有很多重载参数传递给构造函数等等。查看文档:

http://msdn.microsoft.com/en-我们/库/ system.activator.createinstance.aspx

或(新路径)

https://docs.microsoft.com/en-我们/ DOTNET / API / system.activator.createinstance

这里有一些简单的例子:

ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);

ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType");
0
额外
很高兴终于找到了这一点,但第二次调用并不完全正确,缺少一个引用和parms逆转,应该是:ObjectType instance =(ObjectType)Activator.CreateInstance(“MyAssembly”,“MyNamespa‌ ce.ObjectType”);
额外 作者 kevinc,
你需要调用'Unwrap()'来获得你想要的对象的实际类型:ConcreteType实例=(ConcreteType)Activator.CreateInstance(objectType).Unwrap();
额外 作者 Ε Г И І И О,

不使用反射:

private T Create() where T : class, new()
{
    return new T();
}
0
额外
在编译时你知道所有可能的类型,但是你不知道在运行时会使用哪个实现。
额外 作者 Robert P.,
如果您在工厂中使用泛型类和接口,那么实现接口的类型应该是不同的。
额外 作者 Robert P.,
一个新的T();如果T不是具有无参数构造函数的引用类型,则会失败。此方法使用约束来确保T是引用类型并具有构造函数。
额外 作者 Robert P.,
所以T可以在运行时改变。如果你使用deríved类型,这很有用。
额外 作者 Robert P.,
@RobertP。您可以在运行时创建新类型。没有规则说你在编译时知道所有类型。不,我不是用泛型。您可以创建全新的类型,并在运行时添加所有字段,属性和方法等。还有一种简单的情况,你想创建一个在编译时不知道的程序集中的类型实例。这很常见。
额外 作者 AnorZaken,
T在运行时如何变化?你不需要在设计时就知道T来调用Create <>吗?
额外 作者 Kyle Delaney,
这有用吗?您必须知道该类型已经调用该方法,并且如果您知道该类型,则可以在不使用特殊方法的情况下构造该类型。
额外 作者 Kyle Delaney,

我可以跨越这个问题,因为我正在为任意类实现一个简单的CloneObject方法(使用默认构造函数)

通过泛型方法,您可以要求该类型实现New()。

Public Function CloneObject(Of T As New)(ByVal src As T) As T
    Dim result As T = Nothing
    Dim cloneable = TryCast(src, ICloneable)
    If cloneable IsNot Nothing Then
        result = cloneable.Clone()
    Else
        result = New T
        CopySimpleProperties(src, result, Nothing, "clone")
    End If
    Return result
End Function

用非泛型假定类型有一个默认的构造函数和catch 如果不是,则为例外。

Public Function CloneObject(ByVal src As Object) As Object
    Dim result As Object = Nothing
    Dim cloneable As ICloneable
    Try
        cloneable = TryCast(src, ICloneable)
        If cloneable IsNot Nothing Then
            result = cloneable.Clone()
        Else
            result = Activator.CreateInstance(src.GetType())
            CopySimpleProperties(src, result, Nothing, "clone")
        End If
    Catch ex As Exception
        Trace.WriteLine("!!! CloneObject(): " & ex.Message)
    End Try
    Return result
End Function
0
额外

通用的 T t = new T(); 不工作吗?

0
额外
实际上,它将在一个通用的类/方法中,但不适用于给定的“类型”。
额外 作者 Brady Moritz,
ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);

Activator 类具有一个通用的变体,这使得它更容易一些:

ObjectType instance = Activator.CreateInstance();
0
额外
@凯文当然。这样的操作不能用于静态类型语言,因为它没有任何意义。您无法在未知类型的对象上调用方法。与此同时(=自从写这个答案以来)C#已经得到了 dynamic 构造,它允许这样的构造,但对于大多数目的来说,这个答案仍然覆盖它。
额外 作者 Konrad Rudolph,
@AnorZaken我的评论没有提到在运行时创建类型。当然,你可以这样做,但是你不能在同一个环境中静态地使用它们(当然你可以托管一个完整的静态编译程序)。这是我所有的评论都说的。
额外 作者 Konrad Rudolph,
除此之外,对于运行时 Type t 不起作用。
额外 作者 Kevin P. Rice,
@KonradRudolph对不起,曲解“这样的操作”意味着实例化只在运行时才知道的类型;而不是将运行时类型用作泛型类型参数。
额外 作者 AnorZaken,
@KonradRudolph不完全正确。首先c#不允许你在运行时创建新类型。你不能以静态安全的方式给他们打电话。所以,你是一半正确的。但更实际的是,当你在运行时加载程序集时,你需要这个,这意味着类型在编译时不知道。如果你不能这样做,C#会受到严重限制。我的意思是你自己证明了这一点:如何使用类型实例工作的Activator方法呢?当MS编写Activator类时,他们没有编译时知道用户将来编写的任何类型。
额外 作者 AnorZaken,

编译表达式是最好的方式! (用于在运行时反复创建实例的性能)。

static readonly Func YCreator = Expression.Lambda>(
   Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes))
 ).Compile();

X x = YCreator();

统计(2012):

    Iterations: 5000000
    00:00:00.8481762, Activator.CreateInstance(string, string)
    00:00:00.8416930, Activator.CreateInstance(type)
    00:00:06.6236752, ConstructorInfo.Invoke
    00:00:00.1776255, Compiled expression
    00:00:00.0462197, new

统计(2015,.net 4.5,x64):

    Iterations: 5000000
    00:00:00.2659981, Activator.CreateInstance(string, string)
    00:00:00.2603770, Activator.CreateInstance(type)
    00:00:00.7478936, ConstructorInfo.Invoke
    00:00:00.0700757, Compiled expression
    00:00:00.0286710, new

统计(2015,.net 4.5,x86):

    Iterations: 5000000
    00:00:00.3541501, Activator.CreateInstance(string, string)
    00:00:00.3686861, Activator.CreateInstance(type)
    00:00:00.9492354, ConstructorInfo.Invoke
    00:00:00.0719072, Compiled expression
    00:00:00.0229387, new

统计(2017,LINQPad 5.22.02 / x64 / .NET 4.6):

    Iterations: 5000000
    No args
    00:00:00.3897563, Activator.CreateInstance(string assemblyName, string typeName)
    00:00:00.3500748, Activator.CreateInstance(Type type)
    00:00:01.0100714, ConstructorInfo.Invoke
    00:00:00.1375767, Compiled expression
    00:00:00.1337920, Compiled expression (type)
    00:00:00.0593664, new
    Single arg
    00:00:03.9300630, Activator.CreateInstance(Type type)
    00:00:01.3881770, ConstructorInfo.Invoke
    00:00:00.1425534, Compiled expression
    00:00:00.0717409, new

完整代码:

static X CreateY_New()
{
    return new Y();
}

static X CreateY_New_Arg(int z)
{
    return new Y(z);
}

static X CreateY_CreateInstance()
{
    return (X)Activator.CreateInstance(typeof(Y));
}

static X CreateY_CreateInstance_String()
{
    return (X)Activator.CreateInstance("Program", "Y").Unwrap();
}

static X CreateY_CreateInstance_Arg(int z)
{
    return (X)Activator.CreateInstance(typeof(Y), new object[] { z, });
}

private static readonly System.Reflection.ConstructorInfo YConstructor =
    typeof(Y).GetConstructor(Type.EmptyTypes);
private static readonly object[] Empty = new object[] { };
static X CreateY_Invoke()
{
    return (X)YConstructor.Invoke(Empty);
}

private static readonly System.Reflection.ConstructorInfo YConstructor_Arg =
    typeof(Y).GetConstructor(new[] { typeof(int), });
static X CreateY_Invoke_Arg(int z)
{
    return (X)YConstructor_Arg.Invoke(new object[] { z, });
}

private static readonly Func YCreator = Expression.Lambda>(
   Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes))
).Compile();
static X CreateY_CompiledExpression()
{
    return YCreator();
}

private static readonly Func YCreator_Type = Expression.Lambda>(
   Expression.New(typeof(Y))
).Compile();
static X CreateY_CompiledExpression_Type()
{
    return YCreator_Type();
}

private static readonly ParameterExpression YCreator_Arg_Param = Expression.Parameter(typeof(int), "z");
private static readonly Func YCreator_Arg = Expression.Lambda>(
   Expression.New(typeof(Y).GetConstructor(new[] { typeof(int), }), new[] { YCreator_Arg_Param, }),
   YCreator_Arg_Param
).Compile();
static X CreateY_CompiledExpression_Arg(int z)
{
    return YCreator_Arg(z);
}

static void Main(string[] args)
{
    const int iterations = 5000000;

    Console.WriteLine("Iterations: {0}", iterations);

    Console.WriteLine("No args");
    foreach (var creatorInfo in new[]
    {
        new {Name = "Activator.CreateInstance(string assemblyName, string typeName)", Creator = (Func)CreateY_CreateInstance},
        new {Name = "Activator.CreateInstance(Type type)", Creator = (Func)CreateY_CreateInstance},
        new {Name = "ConstructorInfo.Invoke", Creator = (Func)CreateY_Invoke},
        new {Name = "Compiled expression", Creator = (Func)CreateY_CompiledExpression},
        new {Name = "Compiled expression (type)", Creator = (Func)CreateY_CompiledExpression_Type},
        new {Name = "new", Creator = (Func)CreateY_New},
    })
    {
        var creator = creatorInfo.Creator;

        var sum = 0;
        for (var i = 0; i < 1000; i++)
            sum += creator().Z;

        var stopwatch = new Stopwatch();
        stopwatch.Start();
        for (var i = 0; i < iterations; ++i)
        {
            var x = creator();
            sum += x.Z;
        }
        stopwatch.Stop();
        Console.WriteLine("{0}, {1}", stopwatch.Elapsed, creatorInfo.Name);
    }

    Console.WriteLine("Single arg");
    foreach (var creatorInfo in new[]
    {
        new {Name = "Activator.CreateInstance(Type type)", Creator = (Func)CreateY_CreateInstance_Arg},
        new {Name = "ConstructorInfo.Invoke", Creator = (Func)CreateY_Invoke_Arg},
        new {Name = "Compiled expression", Creator = (Func)CreateY_CompiledExpression_Arg},
        new {Name = "new", Creator = (Func)CreateY_New_Arg},
    })
    {
        var creator = creatorInfo.Creator;

        var sum = 0;
        for (var i = 0; i < 1000; i++)
            sum += creator(i).Z;

        var stopwatch = new Stopwatch();
        stopwatch.Start();
        for (var i = 0; i < iterations; ++i)
        {
            var x = creator(i);
            sum += x.Z;
        }
        stopwatch.Stop();
        Console.WriteLine("{0}, {1}", stopwatch.Elapsed, creatorInfo.Name);
    }
}

public class X
{
  public X() { }
  public X(int z) { this.Z = z; }
  public int Z;
}

public class Y : X
{
    public Y() {}
    public Y(int z) : base(z) {}
}
0
额外
或许?
额外 作者 ajeh,
当你不知道什么类型的 X 在运行时时,这仍然有用吗?
额外 作者 ajeh,
还有TypeDescriptor.CreateInstance(请参阅 stackoverflow.com/a/17797389/1242 ),如果使用TypeDescriptor .AddProvider
额外 作者 Lars Truijens,
@ Serj-Tm否,如果类型X是运行时 Type ,则不起作用。
额外 作者 NetMage,
@ajeh是的。将typeof(T)更改为Type.GetType(..)。
额外 作者 Serj-Tm,
所有统计数据+1!目前我并不需要这种表现,但仍然非常有趣。 :)
额外 作者 AnorZaken,

它非常简单。假设您的类名是 Car ,并且名称空间是 Vehicles ,则将参数传递为 Vehicles.Car ,它返回 Car </代码>。像这样,你可以动态地创建任何类的任何实例。

public object GetInstance(string strNamesapace)
{         
     Type t = Type.GetType(strNamesapace); 
     return  Activator.CreateInstance(t);         
}

如果您的完全限定名称(即, Vehicles.Car )在另一个程序集中, Type.GetType 将为空。在这种情况下,您可以遍历所有程序集并找到 Type 。为此,您可以使用下面的代码

public object GetInstance(string strFullyQualifiedName)
{
     Type type = Type.GetType(strFullyQualifiedName);
     if (type != null)
         return Activator.CreateInstance(type);
     foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
     {
         type = asm.GetType(strFullyQualifiedName);
         if (type != null)
             return Activator.CreateInstance(type);
     }
     return null;
 }

你可以通过调用上述方法来获取实例。

object objClassInstance = GetInstance("Vehicles.Car");
0
额外
@danmiser这需要硬编码程序集名称。为了实现灵活性,我检查null并且代码以动态方式工作:)
额外 作者 Sarath Avanavu,
在你的第二种情况下(外部装配),你可以将“Vehicles.Car,OtherAssembly”传递给你的第一个方法,它会起作用。显然,OtherAssembly是它所在组件的名称。
额外 作者 danmiser,

如果这是为了在应用程序实例中调用很多的东西,那么编译和缓存动态代码要快很多,而不是使用激活器或 ConstructorInfo.Invoke()。用于动态编译的两个简单选项可以通过 Linq Expressions 或一些简单的 IL 操作码和 DynamicMethod 。无论哪种方式,当你开始进入紧密循环或多次调用时,差异是巨大的。

0
额外
“IL操作码和DynamicMethod”链接已死亡。
额外 作者 Judge Bread,
public AbstractType New
{
    get
    {
        return (AbstractType) Activator.CreateInstance(GetType());
    }
}
0
额外

如果你想使用默认构造函数,那么使用前面介绍的 System.Activator 解决方案可能是最方便的。但是,如果类型缺少默认构造函数,或者您必须使用非默认构造函数,则选项将使用反射或 System.ComponentModel.TypeDescriptor 。在反射的情况下,知道类型名称(使用其名称空间)就足够了。

使用反射的示例:

ObjectType instance = 
    (ObjectType)System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(
        typeName: objectType.FulName, // string including namespace of the type
        ignoreCase: false,
        bindingAttr: BindingFlags.Default,
        binder: null,  // use default binder
        args: new object[] { args, to, constructor },
        culture: null, // use CultureInfo from current thread
        activationAttributes: null
    );

使用 TypeDescriptor 的示例:

ObjectType instance = 
    (ObjectType)System.ComponentModel.TypeDescriptor.CreateInstance(
        provider: null, // use standard type description provider, which uses reflection
        objectType: objectType,
        argTypes: new Type[] { types, of, args },
        args: new object[] { args, to, constructor }
    );
0
额外

鉴于这个问题,激活器将在有无参数ctor的情况下工作。如果这是一个约束考虑使用

System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()
0
额外