2008-11-28 14 views
426

मैं Type के गुणों के माध्यम से लूप को प्रतिबिंब का उपयोग कर रहा हूं और कुछ प्रकारों को उनके डिफ़ॉल्ट पर सेट कर रहा हूं। अब, मैं इस प्रकार एक स्विच कर सकता हूं और default(Type) स्पष्ट रूप से सेट कर सकता हूं, लेकिन मैं इसे एक पंक्ति में करना चाहता हूं। क्या डिफ़ॉल्ट रूप से प्रोग्रामेटिक समतुल्य है?डिफ़ॉल्ट रूप से प्रोग्रामेटिक समतुल्य (प्रकार)

उत्तर

569
  • एक मान प्रकार उपयोग Activator.CreateInstance के मामले में और यह ठीक काम करना चाहिए।
  • जब संदर्भ प्रकार का उपयोग सिर्फ लौट अशक्त
public static object GetDefault(Type type) 
{ 
    if(type.IsValueType) 
    { 
     return Activator.CreateInstance(type); 
    } 
    return null; 
} 

.net के नए संस्करण में इस तरह के .net मानक के रूप में, type.IsValueType जरूरतों type.GetTypeInfo().IsValueType

+19

यह एक बॉक्स्ड मान प्रकार वापस आ जाएगी और इसलिए डिफ़ॉल्ट (प्रकार) की सटीक बराबर नहीं है। हालांकि, यह उतना करीब है जितना आप जेनरिक के बिना प्राप्त करने जा रहे हैं। –

+6

तो क्या? यदि आपको कोई प्रकार मिलता है जो 'डिफ़ॉल्ट (टी)! = (टी) (ऑब्जेक्ट) डिफ़ॉल्ट (टी) &&! (डिफ़ॉल्ट (टी)! = डिफ़ॉल्ट (टी))' तो आपके पास कोई तर्क है, अन्यथा इससे कोई फ़र्क नहीं पड़ता कि इससे कोई फर्क नहीं पड़ता यह बॉक्स किया गया है या नहीं, क्योंकि वे बराबर हैं। –

+6

अनुमान का अंतिम भाग ऑपरेटर ओवरलोडिंग के साथ धोखाधड़ी से बचने के लिए है ... कोई 'डिफ़ॉल्ट (टी) बना सकता है! = डिफ़ॉल्ट (टी)' झूठी वापसी, और वह धोखा दे रहा है! =) –

4

अभी तक कुछ भी सरल और सुरुचिपूर्ण नहीं मिल रहा है, लेकिन मेरे पास एक विचार है: यदि आप उस संपत्ति के प्रकार को जानते हैं जिसे आप सेट करना चाहते हैं, तो आप अपना खुद का default(T) लिख सकते हैं। दो मामले हैं - T एक मान प्रकार है, और T एक संदर्भ प्रकार है। आप इसे T.IsValueType चेक करके देख सकते हैं। यदि T एक संदर्भ प्रकार है, तो आप इसे आसानी से null पर सेट कर सकते हैं। यदि T एक मान प्रकार है, तो उसके पास एक डिफ़ॉल्ट पैरामीटर रहित कन्स्ट्रक्टर होगा जिसे आप "खाली" मान प्राप्त करने के लिए कॉल कर सकते हैं।

3

मैं इस तरह का एक ही काम करता हूं।

//in MessageHeader 
    private void SetValuesDefault() 
    { 
     MessageHeader header = this;    
     Framework.ObjectPropertyHelper.SetPropertiesToDefault<MessageHeader>(this); 
    } 

//in ObjectPropertyHelper 
    public static void SetPropertiesToDefault<T>(T obj) 
    { 
      Type objectType = typeof(T); 

      System.Reflection.PropertyInfo [] props = objectType.GetProperties(); 

      foreach (System.Reflection.PropertyInfo property in props) 
      { 
       if (property.CanWrite) 
       { 
        string propertyName = property.Name; 
        Type propertyType = property.PropertyType; 

        object value = TypeHelper.DefaultForType(propertyType); 
        property.SetValue(obj, value, null); 
       } 
      } 
    } 

//in TypeHelper 
    public static object DefaultForType(Type targetType) 
    { 
     return targetType.IsValueType ? Activator.CreateInstance(targetType) : null; 
    } 
7

रूप में लिखा जा करने के लिए चुना जवाब एक है अच्छा जवाब है, लेकिन वापस आ गया वस्तु से सावधान रहें।

string test = null; 
string test2 = ""; 
if (test is string) 
    Console.WriteLine("This will never be hit."); 
if (test2 is string) 
    Console.WriteLine("Always hit."); 

Extrapolating ...

string test = GetDefault(typeof(string)); 
if (test is string) 
    Console.WriteLine("This will never be hit."); 
+12

सच है, लेकिन यह डिफ़ॉल्ट रूप से (स्ट्रिंग) के लिए भी है, जैसा कि हर दूसरे संदर्भ प्रकार ... – TDaver

+0

स्ट्रिंग एक विषम पक्षी है - एक वैल्यू प्रकार है जो शून्य को भी वापस कर सकता है। यदि आप कोड को स्ट्रिंग.empty वापस लौटना चाहते हैं तो इसके लिए एक विशेष मामला जोड़ें –

+13

@ डोर - स्ट्रिंग एक अपरिवर्तनीय संदर्भ प्रकार है, न कि मूल्य प्रकार। – ljs

30

आप क्यों कह रहे जेनरिक तस्वीर से बाहर कर रहे हैं?

public static object GetDefault(Type t) 
    { 
     Func<object> f = GetDefault<object>; 
     return f.Method.GetGenericMethodDefinition().MakeGenericMethod(t).Invoke(null, null); 
    } 

    private static T GetDefault<T>() 
    { 
     return default(T); 
    } 
+0

हम्म ... जब मैं कार्यालय वापस आ जाता हूं तो मुझे कोशिश करने दो। मुझे अब तक की सभी परेशानी से गुजरना पड़ेगा। –

+1

अगर केवल मुझे पता था कि यह जल्द ही अस्तित्व में है। जावा पृष्ठभूमि से आने के बाद, मैंने यह भी संभव नहीं माना (जावा का जेनेरिक समर्थन टूटा हुआ है और इसमें न्यूनतम प्रतिबिंब सहायता है)। –

+7

जेनेरिक विधि खोजने के लिए कोई जादू तार की आवश्यकता नहीं है। अच्छा! – Sphinxxx

84

क्यों प्रतिबिंब के साथ डिफ़ॉल्ट (टी) लौटने वाली विधि को कॉल न करें? आप के साथ किसी भी प्रकार की GetDefault उपयोग कर सकते हैं:

public object GetDefault(Type t) 
    { 
     return this.GetType().GetMethod("GetDefaultGeneric").MakeGenericMethod(t).Invoke(this, null); 
    } 

    public T GetDefaultGeneric<T>() 
    { 
     return default(T); 
    } 
+6

यह शानदार है क्योंकि यह इतना आसान है। हालांकि यह सबसे अच्छा समाधान नहीं है, यह ध्यान में रखना एक महत्वपूर्ण समाधान है क्योंकि यह तकनीक कई समान परिस्थितियों में उपयोगी हो सकती है। – configurator

+0

यदि आप जेनेरिक विधि "GetDefault" को इसके बजाए (ओवरलोडिंग) कहते हैं, तो यह करें: यह। गेट टाइप()। GetMethod ("GetDefault", नया प्रकार [0])।

+0

GetDefaultGeneric वापसी 'ऑब्जेक्ट' दें और आप गति के लिए कुछ कैशिंग करने के लिए तैयार हैं। – IllidanS4

5

भाव यहाँ मदद कर सकते हैं:

private static Dictionary<Type, Delegate> lambdasMap = new Dictionary<Type, Delegate>(); 

    private object GetTypedNull(Type type) 
    { 
     Delegate func; 
     if (!lambdasMap.TryGetValue(type, out func)) 
     { 
      var body = Expression.Default(type); 
      var lambda = Expression.Lambda(body); 
      func = lambda.Compile(); 
      lambdasMap[type] = func; 
     } 
     return func.DynamicInvoke(); 
    } 

मैं इस स्निपेट का परीक्षण नहीं किया, लेकिन मुझे लगता है कि यह संदर्भ प्रकारों के लिए "आपके द्वारा लिखा गया" nulls प्रस्तुत करना चाहिए।

+0

' "टाइप किया गया" nulls' के बजाय बेहतर नाम 'nameof (GetDefaultGeneric)' का उपयोग करें - समझाएं। आप किस वस्तु को वापस कर रहे हैं? यदि आप 'टाइप' प्रकार' का ऑब्जेक्ट वापस करते हैं, लेकिन इसका मान 'शून्य' है, तो यह नहीं है - इसके अलावा अन्य कोई अन्य जानकारी नहीं है जो कि यह 'शून्य' है। आप 'शून्य' मान से पूछ नहीं सकते हैं, और यह पता लगा सकते हैं कि यह किस प्रकार का है। यदि आप शून्य नहीं लौटते हैं, लेकिन वापस आते हैं .. मुझे नहीं पता कि .., तो यह 'शून्य' की तरह कार्य नहीं करेगा। – ToolmakerSteve

70

आप PropertyInfo.SetValue(obj, null) का उपयोग कर सकते हैं। यदि किसी मान प्रकार पर कॉल किया जाता है तो यह आपको डिफ़ॉल्ट देगा। यह व्यवहार in .NET 4.0 और in .NET 4.5 दस्तावेज किया गया है।

+4

यह केवल तभी काम करता है यदि आपके पास ऐसी संपत्ति है जिसे आप भरना चाहते हैं? – McKay

+5

इस विशिष्ट प्रश्न के लिए - एक प्रकार की गुणों को लूपिंग और उन्हें "डिफ़ॉल्ट" पर सेट करना - यह शानदार ढंग से काम करता है। प्रतिबिंब का उपयोग कर किसी ऑब्जेक्ट में SqlDataReader से कनवर्ट करते समय मैं इसका उपयोग करता हूं। – Volkirith

2

Dror के जवाब देने के लिए लेकिन एक विस्तार पद्धति के रूप में समतुल्य:

namespace System 
{ 
    public static class TypeExtensions 
    { 
     public static object Default(this Type type) 
     { 
      object output = null; 

      if (type.IsValueType) 
      { 
       output = Activator.CreateInstance(type); 
      } 

      return output; 
     } 
    } 
} 
51

आप .NET 4.0 या इसके बाद के संस्करण उपयोग कर रहे हैं और आप उस कोड का बाहर निर्धारित नियमों के संहिताकरण नहीं है एक कार्यक्रम संबंधी संस्करण चाहते हैं, आप Expression बना सकते हैं, इसे संकलित और चलाएं।

निम्न एक्सटेंशन विधि एक Type लेने के लिए और मूल्य Expression वर्ग पर Default method के माध्यम से default(T) से लौटे मिल जाएगा:

public static T GetDefaultValue<T>() 
{ 
    // We want an Func<T> which returns the default. 
    // Create that expression here. 
    Expression<Func<T>> e = Expression.Lambda<Func<T>>(
     // The default value, always get what the *code* tells us. 
     Expression.Default(typeof(T)) 
    ); 

    // Compile and return the value. 
    return e.Compile()(); 
} 

public static object GetDefaultValue(this Type type) 
{ 
    // Validate parameters. 
    if (type == null) throw new ArgumentNullException("type"); 

    // We want an Func<object> which returns the default. 
    // Create that expression here. 
    Expression<Func<object>> e = Expression.Lambda<Func<object>>(
     // Have to convert to object. 
     Expression.Convert(
      // The default value, always get what the *code* tells us. 
      Expression.Default(type), typeof(object) 
     ) 
    ); 

    // Compile and return the value. 
    return e.Compile()(); 
} 

तुम भी Type के आधार पर ऊपर मूल्य को कैश करना चाहिए, लेकिन अगर बारे में पता होना आप इसे बड़ी संख्या में Type उदाहरणों के लिए बुला रहे हैं, और इसे लगातार उपयोग नहीं करते हैं, कैश द्वारा खपत स्मृति लाभ से अधिक हो सकती है।

+1

यह शानदार है। मैं हमेशा उस एक्टिवेटर चीज़ से सावधान हूं। धन्यवाद। – Jordan

+1

'वापसी प्रकार' के लिए प्रदर्शन। IValueType? एक्टिवेटर। क्रिएट इंस्टेंस (टाइप): शून्य; ' e.Compile()() से 1000x तेज है; – Cyrus

+0

@Cyrus और कैश किए गए मान के लिए? – casperOne

20

यह Flem के समाधान अनुकूलित है:

using System.Collections.Concurrent; 

namespace System 
{ 
    public static class TypeExtension 
    { 
     //a thread-safe way to hold default instances created at run-time 
     private static ConcurrentDictionary<Type, object> typeDefaults = 
      new ConcurrentDictionary<Type, object>(); 

     public static object GetDefaultValue(this Type type) 
     { 
      return type.IsValueType 
       ? typeDefaults.GetOrAdd(type, Activator.CreateInstance) 
       : null; 
     } 
    } 
} 
+2

रिटर्न का एक छोटा सा संस्करण: 'वापसी का प्रकार। IValueType? typeDefaults.GetOrAdd (टाइप, एक्टिवेटर। क्रिएट इंस्टेंस): शून्य; ' –

+3

म्यूटेबल structs के बारे में क्या? क्या आप जानते हैं कि बॉक्सिंग स्ट्रक्चर के फ़ील्ड को संशोधित करना संभव है (और कानूनी), ताकि डेटा बदल जाए? – IllidanS4

+0

@ IllidanS4 विधि के नाम के रूप में यह दर्शाता है कि यह केवल डिफ़ॉल्ट ValueType के मानों के लिए है। – aderesh

1
/// <summary> 
    /// returns the default value of a specified type 
    /// </summary> 
    /// <param name="type"></param> 
    public static object GetDefault(this Type type) 
    { 
     return type.IsValueType ? (!type.IsGenericType ? Activator.CreateInstance(type) : type.GenericTypeArguments[0].GetDefault()) : null; 
    } 
+1

'Nullable ' प्रकारों के लिए काम नहीं करता है: यह 'डिफ़ॉल्ट (Nullable ) के बराबर नहीं लौटाता है, जो 'शून्य' होना चाहिए। ड्रोर द्वारा स्वीकृत उत्तर बेहतर काम करता है। –