পূর্বনির্ধারিত প্রোগ্রামের সমতুল্য (প্রকার)


514

আমি কোনও Typeএর বৈশিষ্ট্যগুলির মধ্যে লুপ প্রতিবিম্ব ব্যবহার করছি এবং তাদের ডিফল্টে নির্দিষ্ট ধরণের সেট করেছি set এখন, আমি টাইপটির উপর একটি স্যুইচ করতে এবং default(Type)স্পষ্টভাবে সেট করতে পারি, তবে আমি এটি বরং এক লাইনে করব। ডিফল্টর সাথে কি প্রোগ্রামিং সমতুল্য আছে?


এটি কাজ করা উচিত: নোলাবল <T> এ = নতুন নুলযোগ্য <টি> () GGetValueOrDefault ();
নর্তকী

উত্তর:


694
  • একটি মান টাইপ ব্যবহারের যদি Activator.CreateInstance এবং এটি সূক্ষ্ম কাজ করা উচিত নয়।
  • রেফারেন্স টাইপ ব্যবহার করার সময় কেবল নাল ফেরান
public static object GetDefault(Type type)
{
   if(type.IsValueType)
   {
      return Activator.CreateInstance(type);
   }
   return null;
}

.Net এর নতুন সংস্করণে যেমন। নেট স্ট্যান্ডার্ড type.IsValueTypeহিসাবে লিখতে হবেtype.GetTypeInfo().IsValueType


22
এটি একটি বক্সযুক্ত মান প্রকারটি ফিরিয়ে দেবে এবং সুতরাং এটি ডিফল্ট (প্রকার) এর সঠিক সমতুল্য নয়। যাইহোক, এটি জেনেরিকগুলি ছাড়াই আপনি যতটা কাছাকাছি চলেছেন তত কাছাকাছি।
রাসেল গিডিংস

8
তাতে কি? যদি আপনি এমন কোনও সন্ধান পান যা default(T) != (T)(object)default(T) && !(default(T) != default(T))তখন আপনার একটি যুক্তি রয়েছে, অন্যথায় এটি বক্স করা আছে কিনা তা বিবেচ্য নয়, কারণ এটি সমতুল্য।
মিগুয়েল অ্যাঞ্জেলো

7
প্রস্তাবকের শেষ টুকরোটি হ'ল অপারেটর ওভারলোডিংয়ের সাথে প্রতারণা করা এড়ানো ... কেউ default(T) != default(T)প্রত্যাবর্তন মিথ্যা করতে পারে , এবং সে প্রতারণা করছে! =)
মিগুয়েল অ্যাঞ্জেলো

4
এটি আমাকে অনেক সাহায্য করেছে, তবে আমি ভেবেছিলাম আমার একটি জিনিস যুক্ত করা উচিত যা এই প্রশ্নটি অনুসন্ধান করার জন্য কিছু লোকের পক্ষে উপযোগী হতে পারে - এছাড়াও যদি আপনি প্রদত্ত ধরণের একটি অ্যারে চান তবে এটি একটি সমতুল্য পদ্ধতিও রয়েছে এবং আপনি এটি ব্যবহার করে এটি পেতে পারেন Array.CreateInstance(type, length)
ড্যারাল হফম্যান

4
আপনি কি অজানা মান ধরণের উদাহরণ তৈরি করার বিষয়ে চিন্তা করবেন না? এটি জামানত প্রভাব থাকতে পারে।
ygormutti

103

প্রতিস্থাপনের সাথে ডিফল্ট (টি) প্রত্যাবর্তনকারী পদ্ধতিটিকে কেন কল করবেন না? আপনি এর সাথে যে কোনও ধরণের গেটডিফল্ট ব্যবহার করতে পারেন:

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

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

7
এটি উজ্জ্বল কারণ এটি খুব সাধারণ। যদিও এটি এখানে সেরা সমাধান নয়, এটি মনে রাখা একটি গুরুত্বপূর্ণ সমাধান কারণ এই কৌশলটি একই রকম পরিস্থিতিতে অনেক ক্ষেত্রে কার্যকর হতে পারে।
কনফিগারকারী

। আপনি জেনেরিক পদ্ধতি "GetDefault" এর পরিবর্তে (ওভারলোডিং) কল পারেন, এই কাজ। This.GetType () GetMethod ( "GetDefault", নতুন ধরনের [0]) <AS_IS>
স্টিফান Steiger

2
মনে রাখবেন, গৃহীত উত্তরের চেয়ে এই বাস্তবায়নটি অনেক ধীর (প্রতিবিম্বের কারণে)। এটি এখনও কার্যকর, তবে পারফরম্যান্সের উন্নতির জন্য আপনাকে গেটমেথড () / মেকগেনেরিকমেথোদ () কলগুলির জন্য কিছু ক্যাচ সেটআপ করতে হবে।
ডগ

1
এটি সম্ভব যে প্রকারের আর্গুমেন্টটি বাতিল। উদাহরণস্বরূপ, কোনও শূন্য পদ্ধতির মেথডবেস.সেসল্টটাইপ () 'টাইপ অবজেক্টটি নাম "শূন্য" বা ফুলনাম "সিস্টেম.ভয়েড" সহ ফিরিয়ে দেবে। অতএব আমি একটি প্রহরী রেখেছি: যদি (t.FullName == "সিস্টেম.ভয়েড") প্রত্যাবর্তন শূন্য; সমাধানের জন্য ধন্যবাদ।
ভালো

8
এর nameof(GetDefaultGeneric)পরিবর্তে আরও ভাল ব্যবহার করুন"GetDefaultGeneric"
মুগেন

87

আপনি ব্যবহার করতে পারেন PropertyInfo.SetValue(obj, null)। যদি কোনও মান প্রকারে কল করা হয় এটি আপনাকে ডিফল্ট দেবে। এই আচরণটি .NET 4.0 এবং .NET 4.5 তে নথিভুক্ত করা হয়েছে


7
এই নির্দিষ্ট প্রশ্নের জন্য - ট্রুপের একটি ধরণের বৈশিষ্ট্যগুলি লুপিং করা এবং তাদের "ডিফল্ট" এ সেট করা - এটি দুর্দান্তভাবে কাজ করে। প্রতিবিম্বের সাহায্যে স্কেলডাটাআরেডার থেকে কোনও বস্তুতে রূপান্তর করার সময় আমি এটি ব্যবহার করি।
আরনো পিটারস

57

যদি আপনি .NET 4.0 বা তদূর্ধ্ব ব্যবহার করছেন এবং আপনি এমন একটি প্রোগ্রামিক সংস্করণ চান যা কোডের বাইরে সংজ্ঞায়িত নিয়মের কোডিকেশন নয় তবে আপনি একটি তৈরি করতে Expression, সংকলন করতে এবং এটিকে অন-ফ্লাইয়ে চালাতে পারেন।

নিম্নলিখিত এক্সটেনশনটি পদ্ধতি গ্রহণ করা হবে Typeএবং থেকে প্রত্যাগত মান পেতে default(T)মাধ্যমে Defaultপদ্ধতি উপর Expressionশ্রেণী:

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দৃষ্টান্তের জন্য কল করছেন , এবং এটি ক্রমাগত ব্যবহার না করেন, ক্যাশে গ্রাহিত মেমরিটি উপকারের চেয়ে বেশি হতে পারে।


4
'রিটার্ন টাইপ.আইএসভ্যালু টাইপের জন্য পারফরম্যান্স? অ্যাক্টিভেটর.ক্রিয়েট ইনস্ট্যান্স (প্রকার): নাল; ' ই। কমপাইল () () এর চেয়ে 1000x দ্রুত;
সাইরাস

1
@Cyrus আমি মোটামুটি আছি নিশ্চিত করুন যে এটি অন্যান্য উপায় বৃত্তাকার হতে হবে যদি আপনি ক্যাশে e.Compile()। এটি প্রকাশের পুরো বিষয়টি point
নওফাল

2
একটি মানদণ্ড চালান। স্পষ্টতই, ফলাফলটি e.Compile()ক্যাশে করা উচিত, তবে ধরে নেওয়া, এই পদ্ধতিটি উদাহরণস্বরূপ প্রায় 14x দ্রুত long। বেঞ্চমার্ক এবং ফলাফলের জন্য gist.github.com/pvginkel/fed5c8512b9dfefc2870c6853bbfbf8b দেখুন ।
পিটার ভ্যান জিনকেল

3
সুদ আউট, কেন ক্যাশে e.Compile()বদলে e.Compile()()? অর্থ্যাৎ রানটাইমের সময় কি কোনও টাইপের ডিফল্ট টাইপ পরিবর্তন হতে পারে? যদি না হয় (যেমনটি আমি বিশ্বাস করি) আপনি কেবল সংকলিত অভিব্যক্তির চেয়ে ফলাফলটি ক্যাশে সঞ্চয় করতে পারেন যা আরও কার্যকারিতা উন্নত করতে পারে।
জনএলবিয়ান

3
@ জোহানএলবেভান - হ্যাঁ, এবং তারপরেও আপনি ফলাফলটি পেতে কোন কৌশলটি ব্যবহার করবেন তা বিবেচনাধীন নয় - সমস্তেরই অত্যন্ত দ্রুততর ইমোরিটাইজড পারফরম্যান্স থাকবে (একটি অভিধানের অনুসন্ধান)।
ড্যানিয়েল আর্উইকার 13

38

আপনি কেন জেনারিক্স চিত্রের বাইরে বলছেন?

    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);
    }

প্রতীক পদ্ধতিটি সমাধান করতে পারে না। উইন্ডোজ জন্য একটি পিসিএল ব্যবহার।
সিউর

1
রান সময়ে জেনেরিক পদ্ধতি তৈরি করা এবং পরপর কয়েক হাজারবার ব্যবহার করা কত ব্যয়বহুল?
সি তেওয়াল্ট

1
আমি এই জাতীয় কিছু সম্পর্কে চিন্তা ছিল। আমার জন্য সেরা এবং সবচেয়ে মার্জিত সমাধান। এমনকি কমপ্যাক্ট ফ্রেমওয়ার্ক 2.0 তে কাজ করে। আপনি যদি পারফরম্যান্স সম্পর্কে চিন্তিত হন, আপনি সর্বদা জেনেরিক পদ্ধতিটি ক্যাশে করতে পারেন, তাই না?
বার্ট

এই সমাধান ঠিক মামলা! ধন্যবাদ!
লাচেজার লালভ

25

এটি ফ্লেমের সমাধানটি অনুকূলিত করেছে:

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
ফিরে আসার একটি সংক্ষিপ্ত সংস্করণ:return type.IsValueType ? typeDefaults.GetOrAdd(type, Activator.CreateInstance) : null;
মার্ক হুইটফিল্ড

3
পরিবর্তনীয় স্ট্রাক্ট সম্পর্কে কী? আপনি কি জানেন যে একটি বাক্সযুক্ত কাঠামোর ক্ষেত্রগুলি সংশোধন করা (এবং আইনী) সম্ভব, যাতে ডেটা পরিবর্তন হয়?
ইলিডানএস 4 মনিকাকে 19 '23

পদ্ধতির নাম হিসাবে @ IllidanS4 এ বোঝায় যে এটি কেবলমাত্র ডিফল্ট মান টাইপ এর মানগুলির জন্য।
আদরেশ

8

নির্বাচিত উত্তরটি একটি ভাল উত্তর, তবে ফিরে আসা অবজেক্টটি সম্পর্কে সতর্ক থাকুন।

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.");

14
সত্য, তবে এটি ডিফল্ট (স্ট্রিং) এর পাশাপাশি প্রতিটি অন্যান্য রেফারেন্স
টাইপও রাখে

স্ট্রিং একটি বিজোড় পাখি - একটি মান ধরণের যা পাশাপাশি নাল ফিরে আসতে পারে। আপনি যদি কোডটি স্ট্রিং.ইম্পটি ফিরিয়ে আনতে চান তবে এটির জন্য কেবল একটি বিশেষ কেস যুক্ত করুন
ডরার হেল্পার

15
@ ডার্ক - স্ট্রিং একটি পরিবর্তনযোগ্য রেফারেন্স টাইপ, কোনও মান ধরণের নয়।
ljs

@ ক্রোনোজ আপনি ঠিক বলেছেন - আমি বোঝাতে চাইছিলাম স্ট্রিংটি স্ট্রিং.ইম্পটি বা প্রয়োজন অনুযায়ী নাল ফিরে দিয়ে পরিচালনা করা যায়।
ড্রয়ার হেল্পার

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();
    }

আমি এই স্নিপেটটি পরীক্ষা করিনি, তবে আমি মনে করি এটির উল্লেখের জন্য "টাইপড" নাল তৈরি করা উচিত ..


1
"typed" nulls- ব্যাখ্যা করা. আপনি কি বস্তু ফিরছেন? আপনি যদি কোনও প্রকারের বস্তুটি ফেরত দেন typeতবে এর মানটি হয় nullতবে তা - ছাড়া - এটি ছাড়া অন্য কোনও তথ্য থাকতে পারে না null। আপনি কোনও nullমান জিজ্ঞাসা করতে পারবেন না এবং এটি কী ধরণের তা অনুমান করা যায়। যদি আপনি শূন্য না ফেরেন তবে ফিরে আসুন .. আমি কী জানি না .., তাহলে এটি পছন্দ করবে না null
টুলমেকারস্টেভ

3

এখনও সহজ এবং মার্জিত কিছু খুঁজে পাচ্ছেন না, তবে আমার একটি ধারণা রয়েছে: আপনি যে ধরণের সম্পত্তি সেট করতে চান তা যদি আপনি জানেন তবে আপনি নিজের লেখা লিখতে পারেন 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;
    }

2

ডারারের উত্তরের সমতুল্য তবে এক্সটেনশন পদ্ধতি হিসাবে:

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;
        }
    }
}

1

@ রব ফোনসেকা-এনসোরের সমাধানের জন্য সামান্য সামঞ্জস্য : নিম্নলিখিত এক্সটেনশন পদ্ধতিটিও কাজ করে।

public static class TypeExtensions
{
    public static object GetDefault(this Type t)
    {
        var defaultValue = typeof(TypeExtensions)
            .GetRuntimeMethod(nameof(GetDefaultGeneric), new Type[] { })
            .MakeGenericMethod(t).Invoke(null, null);
        return defaultValue;
    }

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

... এবং গুণমান সম্পর্কে যত্নশীলদের জন্য সেই ইউনিট পরীক্ষা:

[Fact]
public void GetDefaultTest()
{
    // Arrange
    var type = typeof(DateTime);

    // Act
    var defaultValue = type.GetDefault();

    // Assert
    defaultValue.Should().Be(default(DateTime));
}

0
 /// <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;
    }

2
Nullable<T>ধরণের জন্য কাজ করে না: এটি default(Nullable<T>)যার সমতুল্য হওয়া উচিত তা ফেরায় না null। ড্রয়ার দ্বারা গৃহীত উত্তর আরও ভাল কাজ করে।
সিউর

প্রতিবিম্বটি ব্যবহার করে
অগ্রহণযোগ্য

0

এই কাজ করা উচিত: Nullable<T> a = new Nullable<T>().GetValueOrDefault();

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.