प्रतिबिंब का उपयोग करके C # में डिफ़ॉल्ट निर्माता के बिना प्रकार का उदाहरण बनाना


97

एक उदाहरण के रूप में निम्न वर्ग लें:

class Sometype
{
    int someValue;

    public Sometype(int someValue)
    {
        this.someValue = someValue;
    }
}

मैं तब प्रतिबिंब का उपयोग करके इस प्रकार का एक उदाहरण बनाना चाहता हूं:

Type t = typeof(Sometype);
object o = Activator.CreateInstance(t);

आम तौर पर यह काम करेगा, हालांकि क्योंकि SomeTypeएक पैरामीटर रहित कंस्ट्रक्टर को परिभाषित नहीं किया गया है, कॉल इस संदेश के साथ एक Activator.CreateInstanceप्रकार के अपवाद को फेंक देगा MissingMethodException" इस ऑब्जेक्ट के लिए कोई भी पैरामीटर रहित कंस्ट्रक्टर परिभाषित नहीं है। " क्या अभी भी इस प्रकार का एक उदाहरण बनाने के लिए एक वैकल्पिक तरीका है? यह मेरी सभी कक्षाओं में पैरामीटर रहित कन्स्ट्रक्टरों को जोड़ने के लिए थोथी होगी।


2
FormatterServices.GetUninitializedObjectअसिंचित स्ट्रिंग बनाने की अनुमति नहीं है। आपको अपवाद मिल सकता है: System.ArgumentException: Uninitialized Strings cannot be created.कृपया इसे ध्यान में रखें।
बार्टोज़ पियर्ज़ेलेविच

सिर के लिए धन्यवाद, लेकिन मैं पहले से ही तार और बुनियादी प्रकारों को अलग से संभाल रहा हूं।
आइस्टिना

जवाबों:


142

मैंने मूल रूप से इस उत्तर को यहाँ पोस्ट किया है , लेकिन यहाँ एक पुनर्मुद्रण है क्योंकि यह बिल्कुल समान प्रश्न नहीं है, लेकिन इसका उत्तर भी एक ही है:

FormatterServices.GetUninitializedObject()एक निर्माता को बुलाए बिना एक उदाहरण बनाएगा। मैंने रिफ्लेक्टर का उपयोग करके और कुछ मूल .नेट अनुक्रमिक कक्षाओं के माध्यम से खुदाई करके इस वर्ग को पाया ।

मैंने नीचे दिए गए नमूना कोड का उपयोग करके इसका परीक्षण किया और ऐसा लगता है कि यह बहुत अच्छा काम करता है:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Runtime.Serialization;

namespace NoConstructorThingy
{
    class Program
    {
        static void Main(string[] args)
        {
            MyClass myClass = (MyClass)FormatterServices.GetUninitializedObject(typeof(MyClass)); //does not call ctor
            myClass.One = 1;
            Console.WriteLine(myClass.One); //write "1"
            Console.ReadKey();
        }
    }

    public class MyClass
    {
        public MyClass()
        {
            Console.WriteLine("MyClass ctor called.");
        }

        public int One
        {
            get;
            set;
        }
    }
}

बहुत बढ़िया, ऐसा लगता है कि वास्तव में मुझे क्या चाहिए। मैं मानती हूं कि असंगठित होने का मतलब है कि इसकी सारी मेमोरी शून्य पर सेट हो जाएगी? (
संरचनाएं

प्रत्येक प्रकार के लिए जो भी डिफ़ॉल्ट मान है वह डिफ़ॉल्ट होगा। इसलिए ऑब्जेक्ट्स अशक्त होंगे, 0 अंक, आदि। मुझे लगता है कि कोई भी क्लास-लेवल इनिशियलाइज़ेशन होता है, लेकिन कोई कंस्ट्रक्टर नहीं चलता है।
जेसन जैक्सन

14
@JSBangs, यह बेकार है कि आप एक पूरी तरह से वैध जवाब दे रहे हैं। आपकी टिप्पणी और अन्य उत्तर वास्तव में पूछे गए प्रश्न को संबोधित नहीं करते हैं। यदि आपको लगता है कि आपके पास बेहतर उत्तर है तो एक प्रदान करें। लेकिन मैंने जो उत्तर दिया वह इस बात पर प्रकाश डाला कि कैसे एक दस्तावेज वर्ग का उपयोग किया जाता है उसी तरह अन्य क्रमांकन वर्ग इस कोड का उपयोग करते हैं।
जेसन जैक्सन



72

CreateInstance विधि के इस अधिभार का उपयोग करें:

public static Object CreateInstance(
    Type type,
    params Object[] args
)

कंस्ट्रक्टर का उपयोग करके निर्दिष्ट प्रकार का एक उदाहरण बनाता है जो निर्दिष्ट मापदंडों से सबसे अच्छा मेल खाता है।

देखें: http://msdn.microsoft.com/en-us/library/wcxyzt4d.aspx


1
यह समाधान समस्या की देखरेख करता है। क्या होगा अगर मुझे अपना प्रकार पता नहीं है और मैं कह रहा हूं "बस इस प्रकार के चर में टाइप का एक ऑब्जेक्ट बनाएं"?
कामी

23

जब मैं बेंचमार्क के प्रदर्शन (T)FormatterServices.GetUninitializedObject(typeof(T))में यह धीमी थी। एक ही समय में संकलित अभिव्यक्तियाँ आपको महान गति सुधार देंगी हालांकि वे केवल डिफ़ॉल्ट कंस्ट्रक्टर के साथ काम करते हैं। मैंने एक हाइब्रिड तरीका अपनाया:

public static class New<T>
{
    public static readonly Func<T> Instance = Creator();

    static Func<T> Creator()
    {
        Type t = typeof(T);
        if (t == typeof(string))
            return Expression.Lambda<Func<T>>(Expression.Constant(string.Empty)).Compile();

        if (t.HasDefaultConstructor())
            return Expression.Lambda<Func<T>>(Expression.New(t)).Compile();

        return () => (T)FormatterServices.GetUninitializedObject(t);
    }
}

public static bool HasDefaultConstructor(this Type t)
{
    return t.IsValueType || t.GetConstructor(Type.EmptyTypes) != null;
}

इसका मतलब यह है कि बनाएँ अभिव्यक्ति प्रभावी रूप से कैश की गई है और केवल पहली बार टाइप किए जाने पर जुर्माना लगाती है। एक कुशल तरीके से मूल्य प्रकार भी संभालेंगे।

इसे कहते हैं:

MyType me = New<MyType>.Instance();

ध्यान दें कि (T)FormatterServices.GetUninitializedObject(t)स्ट्रिंग के लिए विफल हो जाएगा। इसलिए स्ट्रिंग के लिए विशेष हैंडलिंग खाली स्ट्रिंग को वापस करने के लिए है।


1
यह अजीब है कि किसी के कोड की एक पंक्ति को एक दिन में कैसे देखा जा सकता है। धन्यवाद महोदय! प्रदर्शन के कारण मुझे आपकी पोस्ट पर ले गए और ट्रिक हो गई :) संकलित अभिव्यक्तियों की तुलना में फॉर्मैटरसर्विस और एक्टिविटर क्लासेस अंडरपरफॉर्म कर रहे हैं, जो एक दयालु है जो सभी जगह पर एक्टिवेटर ढूंढता है।
जम्मोद्रक

@nawfal स्ट्रिंग के लिए आपकी विशेष हैंडलिंग के बारे में, मुझे पता है कि यह इस विशेष हैंडलिंग के बिना स्ट्रिंग के लिए विफल होगा, लेकिन मैं सिर्फ यह जानना चाहता हूं: क्या यह अन्य सभी प्रकारों के लिए काम करेगा ?
Sain atошƒаӽ

@ Sain .ошƒаӽ दुर्भाग्य से नहीं। दिए गए उदाहरण नंगे हैं और .NET में कई अलग-अलग प्रकार के प्रकार हैं। उदाहरण के लिए विचार करें, यदि आप एक प्रतिनिधि प्रकार पास करते हैं तो आप इसे कैसे एक उदाहरण देंगे? वरना अगर कंस्ट्रक्टर फेंकता है तो आप इसके बारे में क्या कर सकते हैं? इसे संभालने के कई अलग-अलग तरीके। मैंने अपनी लाइब्रेरी में बहुत अधिक परिदृश्यों को संभालने के लिए इस अपडेट का जवाब दिया था। यह अब के लिए कहीं भी प्रकाशित नहीं है।
नवाफल

4

अच्छे उत्तर लेकिन डॉट नेट कॉम्पैक्ट फ्रेमवर्क पर अनुपयोगी। यहाँ एक समाधान है जो CF.Net पर काम करेगा ...

class Test
{
    int _myInt;

    public Test(int myInt)
    {
        _myInt = myInt;
    }

    public override string ToString()
    {
        return "My int = " + _myInt.ToString();
    }
}

class Program
{
    static void Main(string[] args)
    {
        var ctor = typeof(Test).GetConstructor(new Type[] { typeof(int) });
        var obj = ctor.Invoke(new object[] { 10 });
        Console.WriteLine(obj);
    }
}

1
यह वह तरीका है जिससे मैं एक गैर-डिफ़ॉल्ट निर्माता को कॉल करूंगा। मुझे यकीन नहीं है कि मैं कभी भी किसी भी निर्माता को बुलाए बिना एक ऑब्जेक्ट बनाना चाहता हूं।
रोरी मैकलेड

2
यदि आप कस्टम धारावाहिक लिख रहे हैं, तो आप कंस्ट्रक्टर्स को कॉल किए बिना एक ऑब्जेक्ट बनाना चाह सकते हैं।
ऑटोडिडैक्ट

1
हाँ, यह सटीक उपयोग मामला परिदृश्य यह सवाल :) के लिए था
Aistina

1
@ ऐस्टिना शायद आप इस जानकारी को प्रश्न में जोड़ सकते हैं? अधिकांश लोग अपने कॉन्टर्स को बुलाए बिना ऑब्जेक्ट बनाने के खिलाफ होंगे और उस बारे में आपसे बहस करने के लिए समय लेंगे, लेकिन आपका उपयोग मामला वास्तव में इसे सही ठहराता है, इसलिए मुझे लगता है कि यह स्वयं प्रश्न के लिए बहुत प्रासंगिक है।
जुलीगॉन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.