জেনেরিক প্যারামিটার হিসাবে নুলযোগ্য টাইপ সম্ভব?


287

আমি এরকম কিছু করতে চাই:

myYear = record.GetValueOrNull<int?>("myYear"),

জেনেরিক প্যারামিটার হিসাবে nallable টাইপ লক্ষ্য করুন।

যেহেতু GetValueOrNullফাংশনটি শূন্য হতে পারে আমার প্রথম প্রচেষ্টাটি ছিল:

public static T GetValueOrNull<T>(this DbDataRecord reader, string columnName)
  where T : class
{
    object columnValue = reader[columnName];

    if (!(columnValue is DBNull))
    {
        return (T)columnValue;
    }
    return null;
}

তবে আমি এখন যে ত্রুটিটি পাচ্ছি তা হ'ল:

টাইপ 'ইনট?' জেনেরিক টাইপ বা পদ্ধতিতে প্যারামিটার 'টি' হিসাবে এটি ব্যবহার করার জন্য অবশ্যই একটি রেফারেন্স টাইপ হতে হবে

রাইট! Nullable<int>একটি struct! সুতরাং আমি শ্রেণি বাধাকে সীমাবদ্ধতায় পরিবর্তন করার চেষ্টা করেছি struct(এবং পার্শ্ব প্রতিক্রিয়া হিসাবে আর কোনও ফিরে আসতে পারে না null):

public static T GetValueOrNull<T>(this DbDataRecord reader, string columnName)
  where T : struct

এখন অ্যাসাইনমেন্ট:

myYear = record.GetValueOrNull<int?>("myYear");

নিম্নলিখিত ত্রুটি দেয়:

টাইপ 'ইনট?' জেনেরিক টাইপ বা পদ্ধতিতে প্যারামিটার 'টি' হিসাবে এটি ব্যবহার করার জন্য অবশ্যই একটি নন-অযোগ্য মান ধরণ হতে হবে

জেনেরিক প্যারামিটার হিসাবে কোনও নালযোগ্য ধরণটি কি সম্ভব সম্ভব?


3
Pls, অনুগ্রহ আপনার স্বাক্ষর করা IDataRecordথেকে DbDataRecord..
nawfal

উত্তর:


262

রিটার্নের ধরণটি নুলেবলে পরিবর্তন করুন এবং নন-নলাবল প্যারামিটার দিয়ে পদ্ধতিটি কল করুন

static void Main(string[] args)
{
    int? i = GetValueOrNull<int>(null, string.Empty);
}


public static Nullable<T> GetValueOrNull<T>(DbDataRecord reader, string columnName) where T : struct
{
    object columnValue = reader[columnName];

    if (!(columnValue is DBNull))
        return (T)columnValue;

    return null;
}

1
আমি আপনাকে পরামর্শ দিচ্ছি যে আপনি "হ'ল" অপারেটরের পরিবর্তে "কলামওয়ালু == ডিবিএন.আলভ" ব্যবহার করুন, কারণ এটির সামান্য দ্রুততর =)
ড্রাইভ ২n

40
ব্যক্তিগত পছন্দ, কিন্তু আপনি সংক্ষিপ্ত রূপ টি ব্যবহার করতে পারেন? পরিবর্তনের পরিবর্তে <টি>
ডান্ক

11
এটি মান ধরণের জন্য ভাল, তবে তারপরে আমি মনে করি এটি রেফারেন্স ধরণের (উদাহরণস্বরূপ GetValueOrNull <string>) দিয়ে মোটেই কাজ করবে না কারণ সি # নুলাবাল পছন্দ করে না বলে মনে হয় (রেফ টাইপ)> "স্ট্রিং?" এর মতো। নীচে রবার্ট সি বার্থ ও জেমস জোনের সমাধানগুলি আপনার প্রয়োজন হলে আমার কাছে আরও ভাল মনে হয়।
বেকার

2
@ ব্যাকার - ঠিক, সুতরাং "যেখানে টি: স্ট্রাক্ট", আপনি যদি রেফারেন্স টাইপ চান তবে আপনি "যেখানে টি: ক্লাস" দিয়ে অনুরূপ পদ্ধতি তৈরি করতে পারেন
গ্রেগ ডিন

4
@ গ্রেগ - নিশ্চিত, তবে তার পরে আপনার দ্বিতীয় পদ্ধতি দরকার এবং আপনি নামটি ওভারলোড করতে পারবেন না। আমি যেমন বলেছি, আপনি যদি ভাল এবং রেফ উভয় ধরণের পরিচালনা করতে চান তবে আমি মনে করি যে ক্লিনার সমাধানগুলি এই পৃষ্ঠায় উপস্থাপন করা হয়েছে।
বেকার

107
public static T GetValueOrDefault<T>(this IDataRecord rdr, int index)
{
    object val = rdr[index];

    if (!(val is DBNull))
        return (T)val;

    return default(T);
}

কেবল এটির মতো ব্যবহার করুন:

decimal? Quantity = rdr.GetValueOrDefault<decimal?>(1);
string Unit = rdr.GetValueOrDefault<string>(2);

6
এটি সংক্ষিপ্ত করা যেতে পারে: রিটার্ন rdr.IsDBNull (সূচক)? ডিফল্ট (টি): (টি) আরডিআর [সূচক];
Foole

11
আমি মনে করি এই প্রশ্নটি স্পষ্টভাবে নাল চায় , ডিফল্ট নয় (টি)
মাফু

5
@ মাফু ডিফল্ট (টি) রেফারেন্স প্রকারের জন্য শূন্য, এবং 0 সংখ্যাগত প্রকারের জন্য ফিরে আসবে, সমাধানটিকে আরও নমনীয় করে তুলবে।
জেমস জোন্স

2
আমি মনে করি এটি স্পষ্ট করে বলা GetValueOrDefaultহয়েছে যে এটির default(T)পরিবর্তে এটি ফিরে আসে null। বিকল্প হিসাবে, আপনি যদি Tএটি অনুসরণযোগ্য না হয় তবে এটি একটি ব্যতিক্রম ছুঁড়ে ফেলতে পারেন ।
স্যাম

এই পদ্ধতিটির অনেক সুবিধা রয়েছে এবং আপনাকে নাল ব্যতীত অন্য কিছু ফেরত দেওয়ার বিষয়ে ভাবতে বাধ্য করে।
শেন

61

শুধু আপনার মূল কোডে দুটি জিনিস করতে - অপসারণ whereবাধ্যতা, এবং শেষ পরিবর্তন returnথেকে return nullথেকেreturn default(T) । আপনি যা চান তা এইভাবে আপনি ফিরে আসতে পারেন।

উপায় দ্বারা, আপনি isআপনার ifবিবৃতিতে পরিবর্তন করে এর ব্যবহার এড়াতে পারেন if (columnValue != DBNull.Value)


4
এই সমাধানটি কার্যকর হয় না, কারণ NUL এবং 0
গ্রেগ ডিন

15
তিনি যে ধরণের পাস করেন তা যদি হয় তবে এটি কাজ করে? এটি যেমন ইচ্ছা তেমন নূলে ফিরে আসবে। যদি তিনি টাইপ হিসাবে int পাস করেন তবে এটি 0 ফিরে আসবে যেহেতু কোনও int NULL হতে পারে না। আমি এটি চেষ্টা করেছি এবং এটি পুরোপুরি কার্যকর হয় তা ছাড়াও।
রবার্ট সি বার্থ 0

2
এটি সবচেয়ে সঠিক এবং নমনীয় উত্তর। তবে, return defaultযথেষ্ট (আপনার দরকার নেই (T), সংকলক স্বাক্ষর ফেরতের ধরণ থেকে এটি নির্ধারণ করবে)।
ম্যাকগুয়ারভি 10

5

দাবি অস্বীকার : এই উত্তরটি কার্যকর হয় তবে এটি কেবলমাত্র শিক্ষামূলক উদ্দেশ্যে। :) জেমস জোন্স এর সমাধান সম্ভবত এখানে সেরা এবং অবশ্যই আমি যেতে চাই।

সি # 4.0 এর dynamicকীওয়ার্ড এটি আরও সহজ করে তোলে, কম নিরাপদ থাকলে:

public static dynamic GetNullableValue(this IDataRecord record, string columnName)
{
  var val = reader[columnName];

  return (val == DBNull.Value ? null : val);
}

এখন আপনার আরএইচএসে সুস্পষ্ট প্রকারের ইঙ্গিতের দরকার নেই:

int? value = myDataReader.GetNullableValue("MyColumnName");

আসলে, আপনি এমনকি এটি প্রয়োজন হয় না!

var value = myDataReader.GetNullableValue("MyColumnName");

value এখন কোনও ইনট, বা একটি স্ট্রিং হবে বা যে কোনও ধরণের ডিবি থেকে ফিরে এসেছে।

একমাত্র সমস্যা হ'ল এটি আপনাকে এলএইচএসে নন-নালাগুলি প্রকারের ব্যবহার থেকে বিরত রাখে না, এক্ষেত্রে আপনি বরং একটি খারাপ বাজে রানটাইম ব্যতিক্রম পাবেন:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot convert null to 'int' because it is a non-nullable value type

যে সমস্ত কোড ব্যবহার করে dynamic: যেমন ক্যাভেট কোডার।


4

ঠিক এর সাথে অবিশ্বাস্য কিছু করতে হয়েছিল। আমার কোড:

public T IsNull<T>(this object value, T nullAlterative)
{
    if(value != DBNull.Value)
    {
        Type type = typeof(T);
        if (type.IsGenericType && 
            type.GetGenericTypeDefinition() == typeof(Nullable<>).GetGenericTypeDefinition())
        {
            type = Nullable.GetUnderlyingType(type);
        }

        return (T)(type.IsEnum ? Enum.ToObject(type, Convert.ToInt32(value)) :
            Convert.ChangeType(value, type));
    }
    else 
        return nullAlternative;
}

3

আমি মনে করি আপনি রেফারেন্সের ধরণ এবং কাঠামোর ধরণগুলি পরিচালনা করতে চান। আমি এটি এক্সএমএল এলিমেন্ট স্ট্রিংগুলিকে আরও টাইপ করা ধরণের রূপান্তর করতে ব্যবহার করি। আপনি প্রতিবিম্ব সহ নালাল বিকল্পটি সরাতে পারেন। ফর্ম্যাটপ্রাইডারটি হ'ল সংস্কৃতি নির্ভর 'handle অথবা ',' বিভাজক যেমন দশমিক বা ints এবং ডাবল। এটি কাজ করতে পারে:

public T GetValueOrNull<T>(string strElementNameToSearchFor, IFormatProvider provider = null ) 
    {
        IFormatProvider theProvider = provider == null ? Provider : provider;
        XElement elm = GetUniqueXElement(strElementNameToSearchFor);

        if (elm == null)
        {
            object o =  Activator.CreateInstance(typeof(T));
            return (T)o; 
        }
        else
        {
            try
            {
                Type type = typeof(T);
                if (type.IsGenericType &&
                type.GetGenericTypeDefinition() == typeof(Nullable<>).GetGenericTypeDefinition())
                {
                    type = Nullable.GetUnderlyingType(type);
                }
                return (T)Convert.ChangeType(elm.Value, type, theProvider); 
            }
            catch (Exception)
            {
                object o = Activator.CreateInstance(typeof(T));
                return (T)o; 
            }
        }
    }

আপনি এটি এর মতো ব্যবহার করতে পারেন:

iRes = helper.GetValueOrNull<int?>("top_overrun_length");
Assert.AreEqual(100, iRes);



decimal? dRes = helper.GetValueOrNull<decimal?>("top_overrun_bend_degrees");
Assert.AreEqual(new Decimal(10.1), dRes);

String strRes = helper.GetValueOrNull<String>("top_overrun_bend_degrees");
Assert.AreEqual("10.1", strRes);

2

এটি একটি মৃত থ্রেড হতে পারে তবে আমি নিম্নলিখিতটি ব্যবহার করতে চাই:

public static T? GetValueOrNull<T>(this DbDataRecord reader, string columnName)
where T : struct 
{
    return reader[columnName] as T?;
}

1
জেনেরিক টাইপ বা পদ্ধতিতে 'T' হিসাবে প্যারামিটার 'T' হিসাবে ব্যবহার করতে 'T' টাইপটি অবশ্যই একটি নন-অযোগ্য মান ধরণের হতে হবে
ইয়ান ওয়ারবার্টন

1

আমি নিজেই একই সমস্যার মুখোমুখি হয়েছি।

... = reader["myYear"] as int?; কাজ করে এবং পরিষ্কার।

এটি কোনও সমস্যা ছাড়াই কোনও প্রকারের সাথে কাজ করে। ফলাফলটি ডিবিএনল হলে রূপান্তর ব্যর্থ হওয়ার সাথে সাথে এটি বাতিল হয়।


আসলে, আপনি সম্ভবত এর int v=reader["myYear"]??-1;পরিবর্তে বা অন্য কোনও ডিফল্ট করতে পারেন -1। যাইহোক, মানটি যদি এই সমস্যাগুলি নিয়ে আসে তবে DBNull...
নুরচি

1

আমি জানি এটি পুরানো, তবে এখানে আরও একটি সমাধান রয়েছে:

public static bool GetValueOrDefault<T>(this SqlDataReader Reader, string ColumnName, out T Result)
{
    try
    {
        object ColumnValue = Reader[ColumnName];

        Result = (ColumnValue!=null && ColumnValue != DBNull.Value) ? (T)ColumnValue : default(T);

        return ColumnValue!=null && ColumnValue != DBNull.Value;
    }
    catch
    {
        // Possibly an invalid cast?
        return false;
    }
}

এখন, আপনি Tমূল্য বা রেফারেন্স ধরণের ছিল কিনা তা যত্নশীল করবেন না । কেবলমাত্র যদি ফাংশনটি সত্য হয়, আপনার ডাটাবেস থেকে যুক্তিসঙ্গত মান থাকবে। ব্যবহার:

...
decimal Quantity;
if (rdr.GetValueOrDefault<decimal>("YourColumnName", out Quantity))
{
    // Do something with Quantity
}

এই পদ্ধতির সাথে খুব মিল int.TryParse("123", out MyInt);


আপনার নামকরণের সম্মেলনে আপনি যদি কাজ করেন তবে ভাল হবে। তাদের ধারাবাহিকতার অভাব রয়েছে। এক জায়গায় মূলধন ব্যতীত একটি ভেরিয়েবল থাকে তবে সেখানে একটি রয়েছে। পদ্ধতিগুলির পরামিতিগুলির সাথে একই।
মেরিনো Šimić

1
কাজ ও সম্পন্ন! আশা কোড এখন আরও ভাল দেখাচ্ছে। বব তোমার আন্টি :) সবই স্কোকুম
নুরচি

0

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

তবে, পদ্ধতিগুলি সঠিকভাবে ব্যবহার হয়েছে কিনা তা নিশ্চিত করতে আপনি জেনেরিক সীমাবদ্ধতাগুলি ব্যবহার করতে পারেন।

আমার ক্ষেত্রে, আমি বিশেষভাবে নালটি ফিরে আসার চেয়েছিলাম এবং কোনও সম্ভাব্য মানের ধরণের ডিফল্ট মান কখনও নয়। GetValueOrDefault = খারাপ। GetValueOrNull = ভাল।

আমি রেফারেন্স ধরণ এবং মান ধরণের মধ্যে পার্থক্য করতে "নুল" এবং "নল" শব্দটি ব্যবহার করেছি। এবং এখানে আমি লিখেছি একটি দম্পতি সম্প্রসারণ পদ্ধতির একটি উদাহরণ যে System.Linq.Eeumerable ক্লাসে ফার্স্টআরডিফল্ট পদ্ধতিটি প্রশংসা করে।

    public static TSource FirstOrNull<TSource>(this IEnumerable<TSource> source)
        where TSource: class
    {
        if (source == null) return null;
        var result = source.FirstOrDefault();   // Default for a class is null
        return result;
    }

    public static TSource? FirstOrNullable<TSource>(this IEnumerable<TSource?> source)
        where TSource : struct
    {
        if (source == null) return null;
        var result = source.FirstOrDefault();   // Default for a nullable is null
        return result;
    }

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