मैं Type
के गुणों के माध्यम से लूप को प्रतिबिंब का उपयोग कर रहा हूं और कुछ प्रकारों को उनके डिफ़ॉल्ट पर सेट कर रहा हूं। अब, मैं इस प्रकार एक स्विच कर सकता हूं और default(Type)
स्पष्ट रूप से सेट कर सकता हूं, लेकिन मैं इसे एक पंक्ति में करना चाहता हूं। क्या डिफ़ॉल्ट रूप से प्रोग्रामेटिक समतुल्य है?डिफ़ॉल्ट रूप से प्रोग्रामेटिक समतुल्य (प्रकार)
उत्तर
- एक मान प्रकार उपयोग Activator.CreateInstance के मामले में और यह ठीक काम करना चाहिए।
- जब संदर्भ प्रकार का उपयोग सिर्फ लौट अशक्त
public static object GetDefault(Type type)
{
if(type.IsValueType)
{
return Activator.CreateInstance(type);
}
return null;
}
.net के नए संस्करण में इस तरह के .net मानक के रूप में, type.IsValueType
जरूरतों type.GetTypeInfo().IsValueType
अभी तक कुछ भी सरल और सुरुचिपूर्ण नहीं मिल रहा है, लेकिन मेरे पास एक विचार है: यदि आप उस संपत्ति के प्रकार को जानते हैं जिसे आप सेट करना चाहते हैं, तो आप अपना खुद का default(T)
लिख सकते हैं। दो मामले हैं - T
एक मान प्रकार है, और T
एक संदर्भ प्रकार है। आप इसे T.IsValueType
चेक करके देख सकते हैं। यदि T
एक संदर्भ प्रकार है, तो आप इसे आसानी से null
पर सेट कर सकते हैं। यदि T
एक मान प्रकार है, तो उसके पास एक डिफ़ॉल्ट पैरामीटर रहित कन्स्ट्रक्टर होगा जिसे आप "खाली" मान प्राप्त करने के लिए कॉल कर सकते हैं।
मैं इस तरह का एक ही काम करता हूं।
//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;
}
रूप में लिखा जा करने के लिए चुना जवाब एक है अच्छा जवाब है, लेकिन वापस आ गया वस्तु से सावधान रहें।
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.");
सच है, लेकिन यह डिफ़ॉल्ट रूप से (स्ट्रिंग) के लिए भी है, जैसा कि हर दूसरे संदर्भ प्रकार ... – TDaver
स्ट्रिंग एक विषम पक्षी है - एक वैल्यू प्रकार है जो शून्य को भी वापस कर सकता है। यदि आप कोड को स्ट्रिंग.empty वापस लौटना चाहते हैं तो इसके लिए एक विशेष मामला जोड़ें –
@ डोर - स्ट्रिंग एक अपरिवर्तनीय संदर्भ प्रकार है, न कि मूल्य प्रकार। – ljs
आप क्यों कह रहे जेनरिक तस्वीर से बाहर कर रहे हैं?
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);
}
हम्म ... जब मैं कार्यालय वापस आ जाता हूं तो मुझे कोशिश करने दो। मुझे अब तक की सभी परेशानी से गुजरना पड़ेगा। –
अगर केवल मुझे पता था कि यह जल्द ही अस्तित्व में है। जावा पृष्ठभूमि से आने के बाद, मैंने यह भी संभव नहीं माना (जावा का जेनेरिक समर्थन टूटा हुआ है और इसमें न्यूनतम प्रतिबिंब सहायता है)। –
जेनेरिक विधि खोजने के लिए कोई जादू तार की आवश्यकता नहीं है। अच्छा! – Sphinxxx
क्यों प्रतिबिंब के साथ डिफ़ॉल्ट (टी) लौटने वाली विधि को कॉल न करें? आप के साथ किसी भी प्रकार की GetDefault उपयोग कर सकते हैं:
public object GetDefault(Type t)
{
return this.GetType().GetMethod("GetDefaultGeneric").MakeGenericMethod(t).Invoke(this, null);
}
public T GetDefaultGeneric<T>()
{
return default(T);
}
यह शानदार है क्योंकि यह इतना आसान है। हालांकि यह सबसे अच्छा समाधान नहीं है, यह ध्यान में रखना एक महत्वपूर्ण समाधान है क्योंकि यह तकनीक कई समान परिस्थितियों में उपयोगी हो सकती है। – configurator
यदि आप जेनेरिक विधि "GetDefault" को इसके बजाए (ओवरलोडिंग) कहते हैं, तो यह करें: यह। गेट टाइप()। GetMethod ("GetDefault", नया प्रकार [0])।
GetDefaultGeneric वापसी 'ऑब्जेक्ट' दें और आप गति के लिए कुछ कैशिंग करने के लिए तैयार हैं। – IllidanS4
भाव यहाँ मदद कर सकते हैं:
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 प्रस्तुत करना चाहिए।
' "टाइप किया गया" nulls' के बजाय बेहतर नाम 'nameof (GetDefaultGeneric)' का उपयोग करें - समझाएं। आप किस वस्तु को वापस कर रहे हैं? यदि आप 'टाइप' प्रकार' का ऑब्जेक्ट वापस करते हैं, लेकिन इसका मान 'शून्य' है, तो यह नहीं है - इसके अलावा अन्य कोई अन्य जानकारी नहीं है जो कि यह 'शून्य' है। आप 'शून्य' मान से पूछ नहीं सकते हैं, और यह पता लगा सकते हैं कि यह किस प्रकार का है। यदि आप शून्य नहीं लौटते हैं, लेकिन वापस आते हैं .. मुझे नहीं पता कि .., तो यह 'शून्य' की तरह कार्य नहीं करेगा। – ToolmakerSteve
आप PropertyInfo.SetValue(obj, null)
का उपयोग कर सकते हैं। यदि किसी मान प्रकार पर कॉल किया जाता है तो यह आपको डिफ़ॉल्ट देगा। यह व्यवहार in .NET 4.0 और in .NET 4.5 दस्तावेज किया गया है।
यह केवल तभी काम करता है यदि आपके पास ऐसी संपत्ति है जिसे आप भरना चाहते हैं? – McKay
इस विशिष्ट प्रश्न के लिए - एक प्रकार की गुणों को लूपिंग और उन्हें "डिफ़ॉल्ट" पर सेट करना - यह शानदार ढंग से काम करता है। प्रतिबिंब का उपयोग कर किसी ऑब्जेक्ट में SqlDataReader से कनवर्ट करते समय मैं इसका उपयोग करता हूं। – Volkirith
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;
}
}
}
आप .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
उदाहरणों के लिए बुला रहे हैं, और इसे लगातार उपयोग नहीं करते हैं, कैश द्वारा खपत स्मृति लाभ से अधिक हो सकती है।
यह 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;
}
}
}
रिटर्न का एक छोटा सा संस्करण: 'वापसी का प्रकार। IValueType? typeDefaults.GetOrAdd (टाइप, एक्टिवेटर। क्रिएट इंस्टेंस): शून्य; ' –
म्यूटेबल structs के बारे में क्या? क्या आप जानते हैं कि बॉक्सिंग स्ट्रक्चर के फ़ील्ड को संशोधित करना संभव है (और कानूनी), ताकि डेटा बदल जाए? – IllidanS4
@ IllidanS4 विधि के नाम के रूप में यह दर्शाता है कि यह केवल डिफ़ॉल्ट ValueType के मानों के लिए है। – aderesh
/// <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;
}
'Nullable
यह एक बॉक्स्ड मान प्रकार वापस आ जाएगी और इसलिए डिफ़ॉल्ट (प्रकार) की सटीक बराबर नहीं है। हालांकि, यह उतना करीब है जितना आप जेनरिक के बिना प्राप्त करने जा रहे हैं। –
तो क्या? यदि आपको कोई प्रकार मिलता है जो 'डिफ़ॉल्ट (टी)! = (टी) (ऑब्जेक्ट) डिफ़ॉल्ट (टी) &&! (डिफ़ॉल्ट (टी)! = डिफ़ॉल्ट (टी))' तो आपके पास कोई तर्क है, अन्यथा इससे कोई फ़र्क नहीं पड़ता कि इससे कोई फर्क नहीं पड़ता यह बॉक्स किया गया है या नहीं, क्योंकि वे बराबर हैं। –
अनुमान का अंतिम भाग ऑपरेटर ओवरलोडिंग के साथ धोखाधड़ी से बचने के लिए है ... कोई 'डिफ़ॉल्ट (टी) बना सकता है! = डिफ़ॉल्ट (टी)' झूठी वापसी, और वह धोखा दे रहा है! =) –