एक प्रकार से एक नई वस्तु उदाहरण कैसे बनाएँ


748

किसी को हमेशा Typeसंकलन-समय पर एक वस्तु का पता नहीं चल सकता है, लेकिन इसका एक उदाहरण बनाने की आवश्यकता हो सकती है Type

कैसे आप एक से एक नई वस्तु उदाहरण मिलता है Type?

जवाबों:


894

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");

20
खुशी है कि आखिरकार यह मिल गया, लेकिन दूसरी कॉल बिल्कुल ठीक नहीं है, एक उद्धरण और पार्स को उलट कर गायब कर दिया जाना चाहिए: ObjectType उदाहरण = (ObjectType) Activator.CreateInstance ("MyAssembly", "MyNamespace.ObjectType");
केविन

9
आप जिस प्रकार की वस्तु चाहते हैं, उसे प्राप्त करने के लिए आपको 'अनवैप ()' को कॉल करने की आवश्यकता है: कंक्रीट टाइप उदाहरण = (कंक्रीट टाइप) एक्टिविटर.क्रीट इनस्टेंस (ऑब्जेक्ट टाइप) .Unwrap ();
14 Г И О И О

4
ObjectType instanceओपी की स्थिति से कैसे मेल खाता है "एक हमेशा संकलन-समय पर किसी वस्तु के प्रकार को नहीं जान सकता है"? : पी
मार्टिन श्नाइडर

@ एमए-मैडिन ठीक है फिर object instance = Activator.CreateInstance(...);,।
BrainSlugs83

1
किसी को पता है कि .NET कोर में यह कैसे करना है? Unwrap विधि ऑब्जेक्ट पर उपलब्ध नहीं है।
जस्टिन

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

Activatorवर्ग एक सामान्य संस्करण में आता है कि यह एक थोड़ा आसान है:

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

8
@ केविन बेशक। इस तरह के एक ऑपरेशन एक सांख्यिकीय रूप से टाइप की गई भाषा में काम नहीं कर सकते क्योंकि यह कोई मतलब नहीं है। आप अज्ञात प्रकार के ऑब्जेक्ट पर विधियों को लागू नहीं कर सकते। इस बीच में (= इस उत्तर लेखन के बाद से) सी # मिल गया है dynamicनिर्माण जो करता है इस तरह के निर्माणों लेकिन सबसे प्रयोजनों के लिए इस सवाल का जवाब अभी भी यह शामिल किया गया है अनुमति देते हैं।
कोनराड रुडोल्फ

1
@KonradRudolph बिल्कुल सच नहीं है। ग # सबसे पहले है आप क्रम में नए प्रकार बनाने के लिए अनुमति देते हैं। आप बस उन पर कुछ भी सुरक्षित तरीके से नहीं कह सकते । तो हाँ, आप आधे सही हैं। लेकिन अधिक वास्तविक रूप से आपको इसकी आवश्यकता तब होती है जब आप असेंबलियों को रनटाइम पर लोड करते हैं, जिसका अर्थ है कि प्रकार संकलन समय पर ज्ञात नहीं है। यदि आप ऐसा नहीं कर सकते तो C # गंभीर रूप से सीमित हो जाएगा मेरा मतलब है कि आपने इसे स्वयं सिद्ध कर दिया है: एक्टिविटर पद्धति किस प्रकार एक और उदाहरण का काम करती है? जब MS ने Activator क्लास लिखी तो उन्हें भविष्य के किसी भी प्रकार के ज्ञान का कोई संकलन नहीं था।
एनरजेड

1
@AnorZaken मेरी टिप्पणी रनटाइम पर प्रकार बनाने के बारे में कुछ नहीं कहती है। बेशक आप ऐसा कर सकते हैं, लेकिन आप उन्हें एक ही संदर्भ में सांख्यिकीय रूप से उपयोग नहीं कर सकते हैं (आप पाठ्यक्रम के पूर्ण संकलित कार्यक्रम की मेजबानी कर सकते हैं)। यह सब मेरी टिप्पणी कह रहा है।
कोनराड रूडोल्फ

@KonradRudolph आह खेद, गलत तरीके से "इस तरह के एक ऑपरेशन" का अर्थ है एक प्रकार का तात्कालिकता जो केवल रनटाइम के लिए जाना जाता है; एक सामान्य प्रकार के पैरामीटर के रूप में रनटाइम प्रकार का उपयोग करने के बजाय अर्थ।
एनरजेन

1
@AnorZaken - तकनीकी रूप से आप रनटाइम पर नए प्रकार बना सकते हैं और उन पर एक विधिपूर्वक सुरक्षित तरीके से कॉल कर सकते हैं यदि आपका नया प्रकार एक ज्ञात इंटरफ़ेस को लागू करता है या एक ज्ञात आधार वर्ग को विरासत में मिला है। - उन दृष्टिकोणों में से कोई भी आपको आपके रनटाइम ऑब्जेक्ट के लिए एक स्थिर अनुबंध देगा।
BrainSlugs83 10

132

संकलित अभिव्यक्ति सबसे अच्छा तरीका है! (रनटाइम में बार-बार उदाहरण बनाने के लिए प्रदर्शन)।

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 / .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

सांख्यिकी (2019, x64 / .NET 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 / .NET कोर 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) {}
}

18
सभी आँकड़ों के लिए +1! मुझे इस समय इस तरह के प्रदर्शन की आवश्यकता नहीं है, लेकिन फिर भी बहुत दिलचस्प है। :)
AnZZaken

1
इसके अलावा वहाँ TypeDescriptor.CreateInstance (देखें है stackoverflow.com/a/17797389/1242 ) जो तेज करता है, तो TypeDescriptor.AddProvider साथ इस्तेमाल किया जा सकता
लार्स Truijens

2
क्या यह तब भी उपयोगी है जब आप नहीं जानते कि Xरनटाइम किस प्रकार का है?
अंजह

1
@ यजीह यस। टाइपऑफ़ (T) को Type.GetType (..) में बदलें।
सेरज-टीएम

3
@ Serj-Tm नहीं, यदि X एक रनटाइम है तो यह काम नहीं करेगा Type
नेटमैज

47

इस समस्या का एक कार्यान्वयन प्रकार के पैरामीटर-कम निर्माता को कॉल करने का प्रयास करना है:

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);
    }
}

15
अपवाद संचालित प्रोग्रामिंग? यह एक बहुत ही खराब कार्यान्वयन की तरह लगता है, जब आप बस निर्माणकर्ताओं को निर्धारित करने के प्रकार पर प्रतिबिंबित कर सकते हैं।
फ़िरोज़ो

16

यह बहुत आसान है। मान लें कि आपका क्लासनाम है 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");

आपके दूसरे मामले में (बाहरी असेंबली), आप बस अपने पहले तरीके के लिए "Vehicles.Car, OtherAssembly" में पास कर सकते हैं और यह काम करेगा। जाहिर है अन्यअसावधान उस विधानसभा का नाम है जिसमें वह रहता है।
danmiser

2
@danmiser जिसे असेंबली नाम कोडिंग की सख्त आवश्यकता है। लचीलेपन को लागू करने के लिए मैं अशक्त और कोड गतिशील तरीके से काम कर रहा हूं :)
सरथ अवनवु

14

यदि यह किसी ऐसी चीज के लिए है जिसे एप्लिकेशन इंस्टेंस में बहुत कुछ कहा जाएगा, तो यह एक्टिवेटर या का उपयोग करने के बजाय गतिशील कोड को संकलित करने और कैश करने के लिए बहुत तेज़ है ConstructorInfo.Invoke()। गतिशील संकलन के लिए दो आसान विकल्प संकलित हैं Linq Expressions या कुछ सरल ILopcodes औरDynamicMethod । किसी भी तरह से, अंतर बहुत बड़ा है जब आप तंग छोरों या कई कॉलों में शामिल होने लगते हैं।


11

जेनेरिक T t = new T();काम नहीं होगा ?


9
वास्तव में, यह एक सामान्य वर्ग / विधि में होगा, लेकिन किसी दिए गए "प्रकार" के लिए नहीं।
ब्रैडी मोरित्ज़

मान लेता है कि टाइप T में 'नया ()' अवरोध है।
रोब वॉन नेसलरोड

10

यदि आप डिफ़ॉल्ट कंस्ट्रक्टर का उपयोग करना चाहते हैं, तो 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 }
    );

args[]वास्तव में क्या मैं इस सवाल के लिए आया था, धन्यवाद!
चाड

10

प्रतिबिंब के उपयोग के बिना:

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

5
यह कैसे उपयोगी है? आपको उस पद्धति को कॉल करने के लिए पहले से ही प्रकार जानना होगा, और यदि आप उस प्रकार को जानते हैं जो आप इसे एक विशेष विधि के बिना बना सकते हैं।
काइल डेलाने

तो T रनटाइम पर अलग-अलग हो सकता है। उपयोगी यदि आप व्युत्पन्न प्रकारों के साथ काम करते हैं।

एक नया टी (); यदि T पैरामीटर पैरामीटर के साथ संदर्भ प्रकार नहीं है, तो यह विफल हो जाएगा, यह विधि T का संदर्भ प्रकार सुनिश्चित करने के लिए विरोधाभासों का उपयोग करती है और एक निर्माता है।

3
T रनटाइम पर कैसे भिन्न हो सकता है? क्या आपको कॉल करने के लिए डिज़ाइन समय पर T पता नहीं है <>?
काइल डेलाने

यदि आप सामान्य वर्ग और कारखानों में इंटरफेस के साथ काम करते हैं, तो इंटरफ़ेस को लागू करने वाले प्रकार अलग-अलग होने चाहिए।

8

इस समस्या को देखते हुए एक्टिवेटर तब काम करेगा जब कोई पैरामीटर रहित ctor हो। यदि यह एक बाधा का उपयोग करने पर विचार करें

System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject()


4

मैं इस प्रश्न को पार कर सकता हूं क्योंकि मैं मनमाने ढंग से वर्ग के लिए एक साधारण क्लोनबॉज विधि लागू करना चाहता था (डिफ़ॉल्ट रचनाकार के साथ)

जेनेरिक विधि के साथ आप की आवश्यकता हो सकती है कि प्रकार नया लागू करता है ()।

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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.