अस्थायी प्रकार के C # सामान्य नए () के लिए तर्क पास करना


409

मैं सूची में जोड़ते समय इसके निर्माता के माध्यम से टाइप टी की एक नई वस्तु बनाने की कोशिश कर रहा हूं।

मुझे एक जटिल त्रुटि मिल रही है: त्रुटि संदेश है:

'T': किसी चर का उदाहरण बनाते समय तर्क प्रदान नहीं कर सकता

लेकिन मेरी कक्षाओं में एक रचनाकार तर्क है! मै इसे काम मे कैसे ले सकता हूँ?

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       tabListItems.Add(new T(listItem)); // error here.
   } 
   ...
}


2
इस कार्यक्षमता को भाषा में लाने का प्रस्ताव: github.com/dotnet/roslyn/issues/2206
इयान केम्प

Microsoft के दस्तावेज़ में, कंपाइलर त्रुटि CS0417 देखें ।
डेविड आरआर

1
भाषा में इस कार्यक्षमता को लाने का प्रस्ताव दिया गया था: github.com/dotnet/csharplang/issues/769
गतिविधि

जवाबों:


410

किसी फ़ंक्शन में एक सामान्य प्रकार की आवृत्ति बनाने के लिए आपको इसे "नए" ध्वज के साथ कसना चाहिए।

public static string GetAllItems<T>(...) where T : new()

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

public static string GetAllItems<T>(..., Func<ListItem,T> del) {
  ...
  List<T> tabListItems = new List<T>();
  foreach (ListItem listItem in listCollection) 
  {
    tabListItems.Add(del(listItem));
  }
  ...
}

फिर आप इसे ऐसा कह सकते हैं

GetAllItems<Foo>(..., l => new Foo(l));

सामान्य वर्ग से आंतरिक रूप से बुलाए जाने पर यह कैसे काम करेगा? मैंने नीचे एक उत्तर में अपना कोड पोस्ट किया है। मैं आंतरिक रूप से ठोस वर्ग को नहीं जानता, क्योंकि यह एक सामान्य वर्ग है। क्या इसका कोई रास्ता है। मैं संपत्ति के
शुरुआती

एक और प्रश्न के लिए मेरे कोड को जोड़ दिया stackoverflow.com/questions/1682310/…
क्रिसका

21
यह वर्तमान में C # की सबसे कष्टप्रद सीमाओं में से एक है। मैं अपनी कक्षाओं को अपरिवर्तनीय बनाना चाहूंगा: केवल निजी बसने से वर्ग को साइड इफेक्ट से अमान्य स्थिति में रखना असंभव होगा। मुझे यह भी पसंद है कि फंक और लैम्ब्डा का उपयोग करना है, लेकिन मुझे पता है कि यह अभी भी व्यापार की दुनिया में एक समस्या है क्योंकि आम तौर पर प्रोग्रामर अभी तक लैम्ब्डा को नहीं जानते हैं और यह आपकी कक्षा को समझने में कठिन बनाता है।
तुओमास हितांन

1
धन्यवाद। मेरे मामले में मुझे कंस्ट्रक्टर के तर्क पता है, जब मैं विधि को बुलाता हूं, तो मुझे टाइप पैरामर की सीमा के आसपास जाने की जरूरत है कि इसे मापदंडों के साथ नहीं बनाया जा सकता है, इसलिए मैंने एक थंक का उपयोग किया । थंक विधि के लिए एक वैकल्पिक पैरामीटर है, और मैं केवल इसका उपयोग करता हूं यदि प्रदान किया जाता है: T result = thunk == null ? new T() : thunk(); मेरे लिए इसका लाभ Tएक जगह में सृजन के तर्क को समेकित करने के बजाय कभी-कभी Tअंदर और कभी-कभी विधि के बाहर बना रहा है।
कार्ल जी

मुझे लगता है कि ये एक ऐसी जगह है जो C # भाषा प्रोग्रामर को ना कहने और हर समय हां कहने का फैसला करती है! हालाँकि यह दृष्टिकोण ऑब्जेक्ट बनाने का थोड़ा अजीब तरीका है, लेकिन मुझे इसे अभी के लिए उपयोग करना है।
अमीरहोसिन रेज़ाई

331

3.5 .Net में 3.5 और बाद में आप एक्टिवेटर क्लास का उपयोग कर सकते हैं:

(T)Activator.CreateInstance(typeof(T), args)

1
हम ऑब्जेक्ट ट्री बनाने के लिए एक्सप्रेशन ट्री का उपयोग भी कर सकते हैं
वेल्ली तम्बुनन

4
आर्ग्स क्या है? एक वस्तु[]?
रॉडने पी। बारबाती

3
हां, आर्ग्स एक वस्तु है [] जहां आप टी के निर्माता को प्रदान किए जाने वाले मूल्यों को निर्दिष्ट करते हैं: "नई वस्तु [] {par1, par2}"
TechNyquist


3
चेतावनी: यदि आपके पास Activator.CreateInstanceइस एक काम के लिए सिर्फ एक समर्पित कंस्ट्रक्टर है, तो ऐसा लगेगा कि आपके कंस्ट्रक्टर का उपयोग बिल्कुल नहीं किया गया है, और कोई व्यक्ति "सफाई" करने और इसे हटाने की कोशिश कर सकता है (रनटाइम त्रुटि का कारण बनने के लिए) भविष्य में कुछ यादृच्छिक समय)। आप एक डमी फ़ंक्शन को जोड़ने पर विचार करना चाह सकते हैं, जहाँ आप इस कंस्ट्रक्टर का उपयोग करते हैं, इसलिए यदि आप इसे हटाने का प्रयास करते हैं तो आपको एक संकलन त्रुटि मिलती है।
जूनियर

51

चूँकि किसी ने भी 'प्रतिबिंब' उत्तर पोस्ट करने की जहमत नहीं उठाई (जो मुझे व्यक्तिगत रूप से सबसे अच्छा जवाब लगता है), यहाँ दिया गया है:

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       Type classType = typeof(T);
       ConstructorInfo classConstructor = classType.GetConstructor(new Type[] { listItem.GetType() });
       T classInstance = (T)classConstructor.Invoke(new object[] { listItem });

       tabListItems.Add(classInstance);
   } 
   ...
}

संपादित करें: यह उत्तर .NET 3.5 के एक्टीवेटर की वजह से हटा दिया गया है। क्रिएशनइन्स्टेंस, हालाँकि यह अभी भी पुराने .NET संस्करणों में उपयोगी है।


मेरी समझ यह है कि अधिकांश प्रदर्शन हिट कंस्ट्रक्टरइन्फो को पहले स्थान पर प्राप्त करने में है। इसे प्रोफाइल किए बिना मेरे शब्द न लें। अगर ऐसा है, तो बाद में पुन: उपयोग के लिए ConstructorInfo को संग्रहीत करना, प्रतिबिंब के साथ दोहराया तात्कालिकता के प्रदर्शन को कम कर सकता है।
केलसी

19
मुझे लगता है कि संकलन-समय की जाँच की कमी चिंता का कारण है।
डेव वान ने आईन्ड

1
@ जेम्स मैं सहमत हूं, मैं इसे "उत्तर" के रूप में नहीं देखकर आश्चर्यचकित था। वास्तव में, मैंने इस प्रश्न पर खोज की थी कि मैं एक अच्छा आसान उदाहरण (आपकी तरह) ढूंढने की उम्मीद कर रहा हूं क्योंकि मैंने प्रतिबिंब बनाने के बाद से यह बहुत लंबा है। वैसे भी, +1 मुझसे, लेकिन एक्टिविटर के जवाब पर भी +1। मैंने देखा कि एक्टिवेटर क्या कर रहा है, और यह पता चला है कि जो कुछ है वह बहुत ही अच्छी तरह से इंजीनियर प्रतिबिंब है। :)
माइक

गेटकंस्ट्रक्टर () कॉल महंगा है, इसलिए यह लूप से पहले कैशिंग के लायक है। इस तरह, लूप के अंदर केवल इनवोक () कॉल करके, यह दोनों को कॉल करने की तुलना में बहुत तेज है या एक्टीवेटर का उपयोग कर रहा है। CreateInstance ()।
कॉसमैन रुस

30

ऑब्जेक्ट इनिशियलाइज़र

यदि पैरामीटर के साथ आपका कंस्ट्रक्टर प्रॉपर्टी सेट करने के अलावा कुछ नहीं कर रहा है, तो आप एक कॉन्ट्रैक्टर को कॉल करने के बजाय एक ऑब्जेक्ट इनिशलाइज़र का उपयोग करके C # 3 या बेहतर तरीके से कर सकते हैं (जो कि असंभव है, जैसा कि उल्लेख किया गया है):

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       tabListItems.Add(new T() { YourPropertyName = listItem } ); // Now using object initializer
   } 
   ...
}

इसका उपयोग करके, आप हमेशा डिफॉल्ट (खाली) कंस्ट्रक्टर में कोई भी कंस्ट्रक्टर लॉजिक डाल सकते हैं।

Activator.CreateInstance ()

वैकल्पिक रूप से, आप Activator.CreateInstance () को कॉल कर सकते हैं :

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
        object[] args = new object[] { listItem };
        tabListItems.Add((T)Activator.CreateInstance(typeof(T), args)); // Now using Activator.CreateInstance
   } 
   ...
}

ध्यान दें कि Activator.CreateInstance में कुछ प्रदर्शन ओवरहेड हो सकते हैं जिनसे आप बचना चाह सकते हैं यदि निष्पादन गति एक सर्वोच्च प्राथमिकता है और एक अन्य विकल्प आपके लिए बनाए रखने योग्य है।


यह Tइसे अपरिवर्तनीय होने से बचाता है (इसमें दिए गए T> 0 निर्भरताएं या आवश्यक मान दिए गए हैं, आप अब ऐसे उदाहरण बना सकते हैं Tजो अमान्य / अनुपयोगी स्थिति में हैं। जब तक Tकि डीटीओ och viewmodel जैसा कुछ मृत सरल नहीं है, मैं कहूंगा कि इससे बचें।
सारा

20

बहुत पुराना प्रश्न, लेकिन नया उत्तर ;-)

एक्सप्रेशनट्री वर्जन : (मुझे लगता है कि व्रत और सबसे साफ समाधान)

जैसे वेली तम्बुनन ने कहा, "हम वस्तु बनाने के लिए अभिव्यक्ति पेड़ का भी उपयोग कर सकते हैं"

यह दिए गए प्रकार / मापदंडों के लिए एक 'कंस्ट्रक्टर' (फ़ंक्शन) उत्पन्न करेगा। यह एक प्रतिनिधि को लौटाता है और पैरामीटर प्रकार को ऑब्जेक्ट की एक सरणी के रूप में स्वीकार करता है।

यह रहा:

// this delegate is just, so you don't have to pass an object array. _(params)_
public delegate object ConstructorDelegate(params object[] args);

public static ConstructorDelegate CreateConstructor(Type type, params Type[] parameters)
{
    // Get the constructor info for these parameters
    var constructorInfo = type.GetConstructor(parameters);

    // define a object[] parameter
    var paramExpr = Expression.Parameter(typeof(Object[]));

    // To feed the constructor with the right parameters, we need to generate an array 
    // of parameters that will be read from the initialize object array argument.
    var constructorParameters = parameters.Select((paramType, index) =>
        // convert the object[index] to the right constructor parameter type.
        Expression.Convert(
            // read a value from the object[index]
            Expression.ArrayAccess(
                paramExpr,
                Expression.Constant(index)),
            paramType)).ToArray();

    // just call the constructor.
    var body = Expression.New(constructorInfo, constructorParameters);

    var constructor = Expression.Lambda<ConstructorDelegate>(body, paramExpr);
    return constructor.Compile();
}

उदाहरण MyClass:

public class MyClass
{
    public int TestInt { get; private set; }
    public string TestString { get; private set; }

    public MyClass(int testInt, string testString)
    {
        TestInt = testInt;
        TestString = testString;
    }
}

उपयोग:

// you should cache this 'constructor'
var myConstructor = CreateConstructor(typeof(MyClass), typeof(int), typeof(string));

// Call the `myConstructor` function to create a new instance.
var myObject = myConstructor(10, "test message");

यहां छवि विवरण दर्ज करें


एक और उदाहरण: एक सरणी के रूप में प्रकारों को पारित करना

var type = typeof(MyClass);
var args = new Type[] { typeof(int), typeof(string) };

// you should cache this 'constructor'
var myConstructor = CreateConstructor(type, args);

// Call the `myConstructor` fucntion to create a new instance.
var myObject = myConstructor(10, "test message");

अभिव्यक्ति का डीबग व्यू

.Lambda #Lambda1<TestExpressionConstructor.MainWindow+ConstructorDelegate>(System.Object[] $var1) {
    .New TestExpressionConstructor.MainWindow+MyClass(
        (System.Int32)$var1[0],
        (System.String)$var1[1])
}

यह उत्पन्न कोड के बराबर है:

public object myConstructor(object[] var1)
{
    return new MyClass(
        (System.Int32)var1[0],
        (System.String)var1[1]);
}

छोटा सा उल्टा

जब वे ऑब्जेक्ट सरणी की तरह पास होते हैं तो सभी वैल्यूएटाइप्स पैरामीटर बॉक्स किए जाते हैं।


सरल प्रदर्शन परीक्षण:

private void TestActivator()
{
    Stopwatch sw = Stopwatch.StartNew();
    for (int i = 0; i < 1024 * 1024 * 10; i++)
    {
        var myObject = Activator.CreateInstance(typeof(MyClass), 10, "test message");
    }
    sw.Stop();
    Trace.WriteLine("Activator: " + sw.Elapsed);
}

private void TestReflection()
{
    var constructorInfo = typeof(MyClass).GetConstructor(new[] { typeof(int), typeof(string) });

    Stopwatch sw = Stopwatch.StartNew();
    for (int i = 0; i < 1024 * 1024 * 10; i++)
    {
        var myObject = constructorInfo.Invoke(new object[] { 10, "test message" });
    }

    sw.Stop();
    Trace.WriteLine("Reflection: " + sw.Elapsed);
}

private void TestExpression()
{
    var myConstructor = CreateConstructor(typeof(MyClass), typeof(int), typeof(string));

    Stopwatch sw = Stopwatch.StartNew();

    for (int i = 0; i < 1024 * 1024 * 10; i++)
    {
        var myObject = myConstructor(10, "test message");
    }

    sw.Stop();
    Trace.WriteLine("Expression: " + sw.Elapsed);
}

TestActivator();
TestReflection();
TestExpression();

परिणाम:

Activator: 00:00:13.8210732
Reflection: 00:00:05.2986945
Expression: 00:00:00.6681696

का उपयोग करना Expressions+/- 8 बार की तुलना में तेज है ConstructorInfoऔर +/- का उपयोग करने की तुलना में 20 गुना तेज हैActivator


क्या आपको इस बात की कोई जानकारी है कि यदि आप निर्माणकर्ता सार्वजनिक MyClass (T डेटा) के साथ MyClass <T> का निर्माण करना चाहते हैं तो क्या करें। इस मामले में, Expression.Convert एक अपवाद फेंकता है और अगर मैं इसे बदलने के लिए सामान्य बाधा बेस क्लास का उपयोग करता हूं, तो Expression.New फेंकता है क्योंकि कंस्ट्रक्टर की जानकारी एक सामान्य प्रकार के लिए है
Mason

@ मेसन (जवाब देने में कुछ समय लगा;;) var myConstructor = CreateConstructor(typeof(MyClass<int>), typeof(int));यह ठीक काम कर रहा है। मुझे नहीं पता।
जीरोन वैन लैंगेन

19

यह आपकी स्थिति में काम नहीं करेगा। आप केवल यह सुनिश्चित कर सकते हैं कि इसमें एक खाली कंस्ट्रक्टर है:

public static string GetAllItems<T>(...) where T: new()

आप इस इंटरफ़ेस को परिभाषित करके संपत्ति इंजेक्शन का उपयोग कर सकते हैं:

public interface ITakesAListItem
{
   ListItem Item { set; }
}

तब आप अपनी विधि को इस प्रकार बदल सकते हैं:

public static string GetAllItems<T>(...) where T : ITakesAListItem, new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       tabListItems.Add(new T() { Item = listItem });
   } 
   ...
}

दूसरा विकल्प Funcजारेडपर द्वारा वर्णित विधि है।


यह किसी भी तर्क को दरकिनार कर देगा जो कि कंस्ट्रक्टर में है जो तर्क लेता है, हालांकि, सही? मैं कुछ करना चाहता हूं जैसे जेरेड का दृष्टिकोण लेकिन मैं कक्षा में आंतरिक रूप से कॉल कर रहा हूं ताकि पता न
चले

3
दाईं ओर, यह T () डिफ़ॉल्ट कंस्ट्रक्टर का तर्क कहता है, फिर बस "आइटम" सेट करता है। यदि आप एक गैर-डिफ़ॉल्ट निर्माता के तर्क को लागू करने की कोशिश कर रहे हैं, तो यह आपकी मदद नहीं करेगा।
स्कॉट स्टैफोर्ड

7

संकलक को यह बताने के लिए कि आपको T: new () कहां जोड़ना है, T को एक डिफ़ॉल्ट कंस्ट्रक्टर प्रदान करने की गारंटी है।

public static string GetAllItems<T>(...) where T: new()

1
अद्यतन: सही त्रुटि संदेश है: 'T': एक चर का उदाहरण बनाते समय तर्क प्रदान नहीं कर सकता
LB.

ऐसा इसलिए है क्योंकि आप एक खाली कंस्ट्रक्टर का उपयोग नहीं कर रहे हैं, आप ऑब्जेक्ट के लिए एक तर्क दे रहे हैं। इसका कोई तरीका नहीं है कि यह निर्दिष्ट किए बिना कि जेनेरिक प्रकार में एक नया (ऑब्जेक्ट) पैरामीटर है।
मिन

फिर आपको या तो करने की आवश्यकता होगी: 1. प्रतिबिंब का उपयोग करें 2. निर्माण के बजाय एक आरंभीकरण विधि में पैरामीटर पास करें, जहां आरंभीकरण विधि एक इंटरफ़ेस से संबंधित है जो आपके प्रकार को लागू करता है और जहां टी में शामिल है: ... घोषणा। विकल्प 1 आपके बाकी कोड के लिए सबसे कम प्रभाव है, लेकिन विकल्प 2 संकलन समय की जाँच प्रदान करता है।
रिचर्ड

प्रतिबिंब का उपयोग न करें! अन्य उत्तरों में उल्लिखित अन्य तरीके हैं जो आपको समान प्रभाव देते हैं।
गैरी शटलर

@ गैरी - मैं सहमत हूँ कि प्रतिबिंब जरूरी नहीं कि सबसे अच्छा तरीका है, लेकिन यह आपको वह हासिल करने की अनुमति देता है जो बाकी कोड आधार में न्यूनतम बदलाव के साथ जरूरी है। उस ने कहा, मैं @JaredPar से फैक्ट्री के प्रतिनिधि के दृष्टिकोण को बहुत पसंद करता हूं।
रिचर्ड

7

यदि आप किसी सदस्य फ़ील्ड या संपत्ति को निर्माता पैरामीटर के साथ C #> = 3 में इनिशियलाइज़ करना चाहते हैं, तो आप इसे बहुत आसान कर सकते हैं:

public static string GetAllItems<T>(...) where T : InterfaceOrBaseClass, new() 
{ 
   ... 
   List<T> tabListItems = new List<T>(); 
   foreach (ListItem listItem in listCollection)  
   { 
       tabListItems.Add(new T{ BaseMemberItem = listItem }); // No error, BaseMemberItem owns to InterfaceOrBaseClass. 
   }  
   ... 
} 

यह वही बात है जिसे गैरी शॉटलर ने कहा था, लेकिन मैं एक सशर्त नोट डालना चाहूंगा।

बेशक आप एक फील्ड वैल्यू सेट करने से ज्यादा सामान बनाने के लिए प्रॉपर्टी ट्रिक का इस्तेमाल कर सकते हैं। एक संपत्ति "सेट ()" अपने संबंधित क्षेत्रों को सेट करने के लिए आवश्यक किसी भी प्रसंस्करण को ट्रिगर कर सकती है और ऑब्जेक्ट के लिए किसी अन्य आवश्यकता को स्वयं जांच सकती है, जिसमें यह देखने के लिए कि क्या ऑब्जेक्ट का उपयोग करने से पहले एक पूर्ण प्रारंभ करना है, एक पूर्ण निर्देश का अनुकरण करता है ( हां, यह एक बदसूरत वर्कअराउंड है, लेकिन यह M $ नए () सीमा से अधिक है।

अगर यह एक नियोजित छेद या आकस्मिक साइड इफेक्ट है, तो मैं आश्वस्त नहीं हो सकता, लेकिन यह काम करता है।

यह बहुत ही हास्यास्पद है कि कैसे एमएस लोग भाषा में नई विशेषताओं को जोड़ते हैं और लगता है कि वे पूर्ण दुष्प्रभाव विश्लेषण नहीं करते हैं। पूरी सामान्य बात इसका एक अच्छा सबूत है ...


1
दोनों बाधाओं की जरूरत है। InterfaceOrBaseClass कंपाइलर को फील्ड / प्रॉपर्टी BaseMemberItem से अवगत कराता है। यदि "नया ()" बाधा पर टिप्पणी की जाती है, तो यह त्रुटि को ट्रिगर करेगा: त्रुटि 6 चर प्रकार 'T' का एक उदाहरण नहीं बना सकता क्योंकि इसमें नया नहीं है () बाधा
fljx

एक स्थिति जिसका मुझे सामना करना पड़ा वह बिल्कुल यहाँ पूछे जा रहे सवाल की तरह नहीं थी, हालाँकि यह जवाब मुझे मिल गया जहाँ मुझे जाने की जरूरत थी और यह बहुत अच्छी तरह से काम करती है।
रूबहॉउस

5
हर बार किसी ने माइक्रोसॉफ्ट को "एम $" के रूप में उल्लेख किया है, मेरी आत्मा का एक छोटा हिस्सा पीड़ित है।
मैथियास लिकेगार्ड लोरेंजेन

6

मैंने पाया कि मुझे एक त्रुटि मिल रही थी "टाइप पैरामीटर टी की एक आवृत्ति बनाते समय तर्क प्रदान नहीं कर सकते" इसलिए मुझे ऐसा करने की आवश्यकता थी:

var x = Activator.CreateInstance(typeof(T), args) as T;

5

यदि आपके पास उस कक्षा तक पहुंच है जिसका आप उपयोग करने जा रहे हैं, तो आप इस दृष्टिकोण का उपयोग कर सकते हैं जो मैंने उपयोग किया था।

एक इंटरफ़ेस बनाएं जिसमें एक वैकल्पिक निर्माता हो:

public interface ICreatable1Param
{
    void PopulateInstance(object Param);
}

एक खाली निर्माता के साथ अपनी कक्षाएं बनाएं और इस पद्धति को लागू करें:

public class MyClass : ICreatable1Param
{
    public MyClass() { //do something or nothing }
    public void PopulateInstance (object Param)
    {
        //populate the class here
    }
}

अब अपने सामान्य तरीकों का उपयोग करें:

public void MyMethod<T>(...) where T : ICreatable1Param, new()
{
    //do stuff
    T newT = new T();
    T.PopulateInstance(Param);
}

यदि आपके पास पहुंच नहीं है, तो लक्ष्य वर्ग लपेटें:

public class MyClass : ICreatable1Param
{
    public WrappedClass WrappedInstance {get; private set; }
    public MyClass() { //do something or nothing }
    public void PopulateInstance (object Param)
    {
        WrappedInstance = new WrappedClass(Param);
    }
}

0

यह मेरी तरह का है, और जब मैं कहता हूं कि मैं बहुत भाग्यशाली हूं, तो मेरा मतलब बगावत करना हो सकता है, लेकिन यह मानकर कि आप अपने पैरामीटर किए गए प्रकार को एक खाली कंस्ट्रक्टर के साथ प्रस्तुत कर सकते हैं, फिर:

public static T GetTInstance<T>() where T: new()
{
    var constructorTypeSignature = new Type[] {typeof (object)};
    var constructorParameters = new object[] {"Create a T"};
    return (T) new T().GetType().GetConstructor(constructorTypeSignature).Invoke(constructorParameters);
}

प्रभावी ढंग से आप एक तर्क के साथ एक पैरामीटर प्रकार से एक वस्तु का निर्माण करने की अनुमति देगा। इस मामले में मैं मान रहा हूं कि मुझे जो कंस्ट्रक्टर चाहिए, उसका एक ही तर्क है object। हम टी का एक डमी उदाहरण बनाते हैं जिसका उपयोग खाली निर्माणकर्ता को अनुमति देता है और फिर उसके अन्य निर्माणकर्ताओं में से एक को प्राप्त करने के लिए प्रतिबिंब का उपयोग करता है।


0

मैं कभी-कभी एक दृष्टिकोण का उपयोग करता हूं जो संपत्ति इंजेक्शन का उपयोग करके जवाबों से मिलता-जुलता है, लेकिन कोड क्लीनर रखता है। गुणों के एक सेट के साथ एक आधार वर्ग / इंटरफ़ेस होने के बजाय, इसमें केवल (वर्चुअल) इनिशियलाइज़ () - विधि शामिल है जो "गरीब आदमी का निर्माण" के रूप में कार्य करती है। फिर आप एक निर्माणकर्ता के रूप में प्रत्येक वर्ग को अपने स्वयं के प्रारंभिककरण को संभालने दे सकते हैं, जो विरासत श्रृंखलाओं को संभालने का एक आश्वस्त तरीका भी जोड़ता है।

यदि अक्सर अपने आप को उन स्थितियों में पाते हैं जहां मैं चाहता हूं कि श्रृंखला में प्रत्येक वर्ग अपने अद्वितीय गुणों को शुरू करने के लिए, और फिर अपने माता-पिता के प्रारंभिक () विधि को कॉल करें जो बदले में माता-पिता के अद्वितीय गुणों और इसके आगे की शुरुआत करता है। विभिन्न वर्गों में होने पर यह विशेष रूप से उपयोगी है, लेकिन एक समान पदानुक्रम के साथ, उदाहरण के लिए व्यावसायिक वस्तुओं को डीटीओ से / के लिए मैप किया जाता है।

उदाहरण जो आरंभिककरण के लिए एक सामान्य शब्दकोश का उपयोग करता है:

void Main()
{
    var values = new Dictionary<string, int> { { "BaseValue", 1 }, { "DerivedValue", 2 } };

    Console.WriteLine(CreateObject<Base>(values).ToString());

    Console.WriteLine(CreateObject<Derived>(values).ToString());
}

public T CreateObject<T>(IDictionary<string, int> values)
    where T : Base, new()
{
    var obj = new T();
    obj.Initialize(values);
    return obj;
}

public class Base
{
    public int BaseValue { get; set; }

    public virtual void Initialize(IDictionary<string, int> values)
    {
        BaseValue = values["BaseValue"];
    }

    public override string ToString()
    {
        return "BaseValue = " + BaseValue;
    }
}

public class Derived : Base
{
    public int DerivedValue { get; set; }

    public override void Initialize(IDictionary<string, int> values)
    {
        base.Initialize(values);
        DerivedValue = values["DerivedValue"];
    }

    public override string ToString()
    {       
        return base.ToString() + ", DerivedValue = " + DerivedValue;
    }
}

0

यदि आप सभी की आवश्यकता है तो ListItem से अपने टाइप टी में रूपांतरण है आप इस रूपांतरण को टी ऑपरेटर में रूपांतरण ऑपरेटर के रूप में लागू कर सकते हैं।

public class T
{
    public static implicit operator T(ListItem listItem) => /* ... */;
}

public static string GetAllItems(...)
{
    ...
    List<T> tabListItems = new List<T>();
    foreach (ListItem listItem in listCollection) 
    {
        tabListItems.Add(listItem);
    } 
    ...
}

-4

मेरा मानना ​​है कि आपको एक नए निर्माणकर्ता के साथ वस्तुओं को अनुमति देने के लिए एक बयान के साथ टी को कसना होगा।

अब यह इसके बिना वस्तुओं सहित कुछ भी स्वीकार करता है।


1
आप इस उत्तर को बदलना चाह सकते हैं क्योंकि यह आपके द्वारा उत्तर दिए जाने के बाद प्रश्न में संपादित हो जाता है जो इस उत्तर को संदर्भ से बाहर कर देता है।
शटल87
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.