2010-04-09 21 views
13

पर सामान्य प्रकार की स्थापना मैं एक वर्गक्रम

public class A<T> 
{ 
    public static string B(T obj) 
    { 
     return TransformThisObjectToAString(obj); 
    } 
} 

है स्ट्रिंग के उपयोग के ऊपर विशुद्ध रूप से अनुकरणीय है। मैं इस तरह स्थिर समारोह सिर्फ एक ज्ञात/निर्दिष्ट प्रकार पर ठीक कॉल कर सकते हैं:

string s= A<KnownType>.B(objectOfKnownType); 

मैं इस कॉल कैसे कर सकता हूँ, अगर मैं टी पहले से पता नहीं है, बल्कि मैं प्रकार के एक चर है प्रकार टाइप करें जो प्रकार रखता है। मैं ऐसा करते हैं तो:

Cannot implicitly convert type 't' to 'object' 
+0

बंद [सी तेज गतिशील-सामान्य प्रकार] (http://stackoverflow.com/questions/2078914/c-sharp- गतिशील-जेनेरिक-प्रकार) – nawfal

उत्तर

9

आप नहीं कर सकते हैं:

Type t= typeof(string); 
string s= A<t>.B(someStringObject); 

मैं इस संकलक त्रुटि मिलती है। जेनेरिक प्रकार पहचानकर्ताओं को संकलन समय पर जाना जाना चाहिए। जो पाठ्यक्रम के खतरों है -

संपादित

अन्य पदों के रूप में

, यह dynamicly विधि पैदा करने और इसे लागू करने से संभव प्रतीत होता है। अधिक जानकारी के लिए थॉमस और डाथन की पोस्ट देखें।

+0

मुझे लगता है कि मैंने प्रश्न को गलत तरीके से पढ़ा है। जो कुछ आपने कहा है उससे परे कुछ भी वास्तव में जोड़ नहीं सकते हैं। – ChaosPandion

+3

यह कहना अधिक सटीक होगा कि ऐसा करने के लिए कोई स्थैतिक रूप से टाइप किया गया तरीका नहीं है; या शायद कोई मूर्खतापूर्ण तरीका नहीं है। लेकिन जैसा कि टॉमस और मेरे जवाब दिखाते हैं, विधि को गतिशील रूप से हल किया जा सकता है और मनमाने ढंग से तर्क के साथ रनटाइम पर बुलाया जा सकता है। – Dathan

+0

में संपादित, धन्यवाद – Femaref

0

रनटाइम पर प्रकार पैरामीटर को प्रतिस्थापित करने का प्रयास करने से पूरे प्रकार के प्रकार को सुरक्षित किया जाएगा, जिसे सी # कंपाइलर द्वारा लागू किया जाता है। सी # कंपाइलर सूर्स बनाता है जो टाइप पैरामीटर संकलन समय पर निर्दिष्ट होते हैं और रनटाइम पर टाइप तर्कों पर कोई अस्पष्टता नहीं होती है। मुझे संदेह है कि आप जेनेरिक टाइप में रनटाइम पर टाइप पैरामीटर को प्रतिस्थापित कर सकते हैं। "टाइप" टाइपिंग टाइपिंग तर्क का प्रकार लगभग एक अनबाउंड जेनेरिक प्रकार है।

19

आप इसे सीधे नहीं कर सकते हैं, लेकिन आप रन-टाइम पर कक्षा के प्रकार पैरामीटर प्रदान करने के लिए प्रतिबिंब का उपयोग कर सकते हैं। मैं इस परीक्षण नहीं किया है, लेकिन कुछ इस तरह काम करना चाहिए:

// We want to do something like this: 
// object o = "Hello" 
// Type t = o.GetType(); 
// 
// This is pseudo-code only: 
// string s = A<t>.B(o); 

string InvokeA(object o) { 
    // Specify the type parameter of the A<> type 
    Type genericType = typeof(A<>).MakeGenericType(new Type[] { o.GetType() }); 
    // Get the 'B' method and invoke it: 
    object res = genericType.GetMethod("B").Invoke(new object[] { o }); 
    // Convert the result to string & return it 
    return (string)res; 
} 
बेशक

, सवाल यह है कि अगर यह वास्तव में आप क्या जरूरत है - आप एक तर्क के रूप में दिया वस्तु के बारे में कुछ भी पता नहीं है, आप ऑब्जेक्ट का उपयोग करके पूरे कोड को भी लिख सकते हैं। हालांकि, मैं कुछ परिदृश्यों की कल्पना कर सकता हूं जहां यह उपयोगी होगा, इसलिए मुझे लगता है कि आप इसका उपयोग करने का प्रयास कर सकते हैं।

+0

ओह, मुझे एहसास नहीं हुआ कि आप 'ए <> 'से' टाइपऑफ()' पास कर सकते हैं। आपका कोड मेरी तुलना में निश्चित रूप से साफ है। बहुत बढ़िया। – Dathan

+0

मुझे वास्तव में यह तथ्य पसंद नहीं है कि आप 'ए <>' सी # में लिख सकते हैं क्योंकि यह _really_ एक प्रकार नहीं है। यह एक अजीब बात है। वैसे भी, मुझे लगता है कि यह कभी-कभी उपयोगी होता है :-)। –

+0

'ए <>' लिखना, और 'बाहरी <,>' जैसी चीजें। <,,,> '' टाइपोफ "तर्क के लिए उपयोगी है, लेकिन यह एक अच्छी बात है कि अन्य संदर्भों में इसकी अनुमति नहीं है क्योंकि आप सही हैं, यह सही नहीं है सी # प्रकार। –

7

ढांचे और सीएलआर में इसके लिए बिल्कुल समर्थन है - सी # में बस शानदार नहीं है। एक सहायक विधि की सहायता से आप जो भी सोचते हैं, उसे पूरा कर सकते हैं:

public class A<T> 
{ 
    public static string B(T obj) 
    { 
     return obj.ToString(); 
    } 
} 

public class MyClass 
{ 
    public static void DoExample() 
    { 
     Console.WriteLine(ExecuteB("Hi")); 
     Console.WriteLine(ExecuteB(DateTime.Now)); 
    } 

    public static object ExecuteB(object arg) 
    { 
     Type arg_type = arg.GetType(); 
     Type class_type = typeof(MyClass); 
     MethodInfo mi = class_type.GetMethod("ExecuteBGeneric", BindingFlags.Static | BindingFlags.Public); 
     MethodInfo mi2 = mi.MakeGenericMethod(new Type[] { arg_type }); 
     return mi2.Invoke(null, new object[] { arg }); 
    } 

    public static object ExecuteBGeneric<T>(T arg) 
    { 
     return A<T>.B(arg); 
    } 
1

आप नहीं कर सकते। लेकिन आपने दिए गए मामले के लिए गलत सवाल पूछा है। इस मामले में (जैसा कि 99% मामलों में) आपको वास्तव में टाइप बाधा है।

प्रयास करें:

public class A<T> where T : object 

या, यदि टी एक ज्ञात वर्ग, एक उपवर्ग, या एक अंतरफलक है तो यह

public class A<T> where T : YourAbstractClass 

अन्य प्रकार की कमी उपयोग करने के लिए भी मौजूद हैं बेहतर होगा।अधिक विवरण: http://msdn.microsoft.com/en-us/library/d5x73970(VS.80).aspx

एक सामान्य नोट के रूप में, जब एक नई भाषा सीखना, आप अक्सर मोटे तौर पर क्या आप करना चाहते हैं प्राप्त के बारे में सोचना, विशेष रूप से क्या आप को करना चाहते हैं नहीं मिल रहा। यह असली दुनिया मौखिक भाषाओं की तरह है। एक शब्दकोष पढ़कर और शब्दों को अंग्रेजी वाक्यविन्यास में लिखने, या वाक्यविन्यास सीखने और शब्दों को उठाकर जर्मन सीखने के बीच यह अंतर है। हां, एक जर्मन स्पीकर किसी ऐसे व्यक्ति को समझ जाएगा जो एक शब्दकोश से बात कर रहा है, लेकिन डब्ल्यूटीएफ प्रति वाक्य गणना बहुत अधिक होगी।

0

मैंने यहां कुछ जवाबों के आधार पर इस सहायक विधि को बनाया है, अन्यथा जहां वेब पर।

उपयोग:

InvokeGenericMethodWithRuntimeGenericArguments(MyMethodWithGenericType<IType>, new[] {MyRuntimeGenericType}, null); 

विधि:

public static object InvokeGenericMethodWithRuntimeGenericArguments(Action methodDelegate, Type[] runtimeGenericArguments, params object[] parameters) 
     { 
      if (parameters == null) 
      { 
       parameters = new object[0]; 
      } 
      if (runtimeGenericArguments == null) 
      { 
       runtimeGenericArguments = new Type[0]; 
      } 

      var myMethod = methodDelegate.Target.GetType() 
         .GetMethods() 
         .Where(m => m.Name == methodDelegate.Method.Name) 
         .Select(m => new 
         { 
          Method = m, 
          Params = m.GetParameters(), 
          Args = m.GetGenericArguments() 
         }) 
         .Where(x => x.Params.Length == parameters.Length 
            && x.Args.Length == runtimeGenericArguments.Length 
         ) 
         .Select(x => x.Method) 
         .First().MakeGenericMethod(runtimeGenericArguments); 
      return myMethod.Invoke(methodDelegate.Target, parameters); 
     }