سؤال

واحدة قد لا نعرف دائما Type كائن في وقت التحويل البرمجي ، ولكن قد تحتاج إلى إنشاء مثيل Type.كيف يمكنك الحصول على كائن جديد مثيل من Type?

هل كانت مفيدة؟

المحلول

على Activator فئة داخل الجذر System مساحة جميلة قوية.

هناك الكثير من الزائدة من أجل تمرير المعلمات إلى منشئ هذه.تحقق من الوثائق في:

http://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx

أو (مسار جديد)

https://docs.microsoft.com/en-us/dotnet/api/system.activator.createinstance

وهنا بعض الأمثلة البسيطة:

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

ObjectType instance = (ObjectType)Activator.CreateInstance("MyAssembly","MyNamespace.ObjectType");

نصائح أخرى

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

على Activator فئة عامة البديل الذي يجعل هذا أسهل قليلا:

ObjectType instance = Activator.CreateInstance<ObjectType>();

جمعت التعبير هو أفضل طريقة!(بالنسبة إلى الأداء مرارا وتكرارا إنشاء مثيل في وقت التشغيل).

static readonly Func<X> YCreator = Expression.Lambda<Func<X>>(
   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/.صافي 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

الإحصاءات (2019, x64/.صافي 4.8):

Iterations: 5000000
No args
00:00:00.3287835, Activator.CreateInstance(string assemblyName, string typeName)
00:00:00.3122015, Activator.CreateInstance(Type type)
00:00:00.8035712, ConstructorInfo.Invoke
00:00:00.0692854, Compiled expression
00:00:00.0662223, Compiled expression (type)
00:00:00.0337862, new
Single arg
00:00:03.8081959, Activator.CreateInstance(Type type)
00:00:01.2507642, ConstructorInfo.Invoke
00:00:00.0671756, Compiled expression
00:00:00.0301489, new

الإحصاءات (2019, x64/.صافي Core 3.0):

Iterations: 5000000
No args
00:00:00.3226895, Activator.CreateInstance(string assemblyName, string typeName)
00:00:00.2786803, Activator.CreateInstance(Type type)
00:00:00.6183554, ConstructorInfo.Invoke
00:00:00.0483217, Compiled expression
00:00:00.0485119, Compiled expression (type)
00:00:00.0434534, new
Single arg
00:00:03.4389401, Activator.CreateInstance(Type type)
00:00:01.0803609, ConstructorInfo.Invoke
00:00:00.0554756, Compiled expression
00:00:00.0462232, 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<X> YCreator = Expression.Lambda<Func<X>>(
   Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes))
).Compile();
static X CreateY_CompiledExpression()
{
    return YCreator();
}

private static readonly Func<X> YCreator_Type = Expression.Lambda<Func<X>>(
   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<int, X> YCreator_Arg = Expression.Lambda<Func<int, X>>(
   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<X>)CreateY_CreateInstance},
        new {Name = "Activator.CreateInstance(Type type)", Creator = (Func<X>)CreateY_CreateInstance},
        new {Name = "ConstructorInfo.Invoke", Creator = (Func<X>)CreateY_Invoke},
        new {Name = "Compiled expression", Creator = (Func<X>)CreateY_CompiledExpression},
        new {Name = "Compiled expression (type)", Creator = (Func<X>)CreateY_CompiledExpression_Type},
        new {Name = "new", Creator = (Func<X>)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<int, X>)CreateY_CreateInstance_Arg},
        new {Name = "ConstructorInfo.Invoke", Creator = (Func<int, X>)CreateY_Invoke_Arg},
        new {Name = "Compiled expression", Creator = (Func<int, X>)CreateY_CompiledExpression_Arg},
        new {Name = "new", Creator = (Func<int, X>)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) {}
}

واحد تنفيذ هذه المشكلة هو محاولة استدعاء المعلمة أقل منشئ من نوع:

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

هنا هو نفس النهج الوارد في طريقة عامة:

public static T GetNewObject<T>()
{
    try
    {
        return (T)typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { });
    }
    catch
    {
        return default(T);
    }
}

دورته بسيطة جدا.نفترض أن classname هو Car و الاسم هو Vehicles, ثم تمرير المعلمة Vehicles.Car التي تقوم بإرجاع كائن من نوع Car.مثل هذا يمكنك إنشاء أي مثيل من أي فئة حيوي.

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

إذا كان الخاص بك اسم مؤهل بشكل كامل(ie ، 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");

إذا كان هذا هو شيء من شأنها أن يسمى الكثير في تطبيق سبيل المثال ، الكثير أسرع تجميع ذاكرة التخزين المؤقت رمز الحيوي بدلا من استخدام المنشط أو ConstructorInfo.Invoke().اثنين من خيارات سهلة الحيوية تجميع تجميع Linq التعبير أو بعض بسيطة IL opcodes ، DynamicMethod.وفي كلتا الحالتين, والفرق كبير عند بدء الدخول في حلقات ضيقة أو مكالمات متعددة.

دون استخدام التفكير:

private T Create<T>() where T : class, new()
{
    return new T();
}

لا عامة T t = new T(); العمل ؟

إذا كنت ترغب في استخدام منشئ افتراضي ثم الحل باستخدام 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 }
    );

ونظرا لهذه المشكلة المنشط سوف تعمل عندما يكون هناك parameterless المنشئ.إذا كان هذا هو القيد النظر في استخدام

System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()

يمكنني عبر هذا السؤال لأنني كنت تبحث عن تطبيق بسيط CloneObject الأسلوب التعسفي فئة (مع منشئ افتراضي)

مع عامة الطريقة يمكنك أن تطلب أن نوع الأدوات الجديدة().

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

مع عدم عامة تفترض نوع منشئ افتراضي وقبض استثناء إذا كان لا.

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
public AbstractType New
{
    get
    {
        return (AbstractType) Activator.CreateInstance(GetType());
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top