রূপান্তর করুন.চেনজ টাইপ () নুলযোগ্য প্রকারভেদে ব্যর্থ


301

আমি একটি স্ট্রিংকে একটি অবজেক্ট প্রোপার্টি মানতে রূপান্তর করতে চাই, যার নামটি একটি স্ট্রিং হিসাবে আমার রয়েছে। আমি এটির মতো করার চেষ্টা করছি:

string modelProperty = "Some Property Name";
string value = "SomeValue";
var property = entity.GetType().GetProperty(modelProperty);
if (property != null) {
    property.SetValue(entity, 
        Convert.ChangeType(value, property.PropertyType), null);
}

সমস্যাটি হ'ল এটি ব্যর্থ হচ্ছে এবং যখন সম্পত্তি প্রকারটি একটি প্রকারভেদযোগ্য টাইপ হয় তখন একটি অবৈধ কাস্ট ব্যতিক্রম ছুঁড়ে ফেলা হয়। মানগুলি রূপান্তরিত করতে অক্ষম হওয়ার ক্ষেত্রে এটি নয় - আমি নিজে থেকে এটি করা হলে তারা কাজ করবে (উদাহরণস্বরূপ DateTime? d = Convert.ToDateTime(value);) আমি কিছু সাদৃশ্যমূলক প্রশ্ন দেখেছি কিন্তু এখনও এটি কাজ করতে পারছি না।


1
আমি পেটাপোকো ৩.০.৩ এর সাথে এক্সিকিউটিস্ক্যালার <int?> ব্যবহার করছি এবং এটি একই কারণে ব্যর্থ: রিটার্ন (টি) রূপান্তর করুন han৫৪-তে লাইভ টাইপফ (টি)
ল্যারি

উত্তর:


409

স্বীকৃত, তবে সম্ভবত এর মতো কিছু কাজ করবে:

string modelProperty = "Some Property Name";
string value = "Some Value";

var property = entity.GetType().GetProperty(modelProperty);
if (property != null)
{
    Type t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;

    object safeValue = (value == null) ? null : Convert.ChangeType(value, t);

    property.SetValue(entity, safeValue, null);
}

12
শুধু কোডটির এই টুকরোটি আমার দরকার ছিল। নলাবল.গেটউন্ডারিলিংটাইপের জন্য ধন্যবাদ! যখন আমি একটি প্রকল্প প্রয়োজন তার জন্য যখন একজন দরিদ্র ব্যক্তির মডেলবাইন্ডার তৈরি করি তখন আমাকে অনেক সাহায্য করেছিল। আমি আপনাকে একটি বিয়ার পাওনা!
ম্যাক্সিমাম রৌইলার

3
পরিবর্তে (value == null) ? nullব্যবহারের বদলে (value == null) ? default(t)?
থ্রেডস্টার

স্ট্রিং থেকে ইউনিক পরিচয়দাতার পক্ষে কাজ করছে বলে মনে হচ্ছে না।
অ্যান্ডারস লিন্ডন

safeValueকেবল পুনরায় নিয়োগের বিপরীতে ভেরিয়েবলটি তৈরি করার কোনও বিশেষ কারণ আছে কি value?
coloradocolby

@ থ্রেডস্টার আপনি 'টাইপ' টাইপের ডিফল্ট অপারেটর ওণা ভেরিয়েবল ব্যবহার করতে পারবেন না। দেখুন stackoverflow.com/questions/325426/...
andy250

75

এটি করতে আপনাকে অন্তর্নিহিত টাইপটি পেতে হবে ...

এটি চেষ্টা করুন, আমি জেনারিকের সাথে এটি সফলভাবে ব্যবহার করেছি:

//Coalesce to get actual property type...
Type t = property.PropertyType();
t = Nullable.GetUnderlyingType(t) ?? t;

//Coalesce to set the safe value using default(t) or the safe type.
safeValue = value == null ? default(t) : Convert.ChangeType(value, t);

আমি এটি আমার কোডের বেশ কয়েকটি স্থানে ব্যবহার করি, একটি উদাহরণ হ'ল একটি সহায়ক পদ্ধতি যা আমি টাইপসেফ পদ্ধতিতে ডাটাবেস মান রূপান্তর করতে ব্যবহার করি:

public static T GetValue<T>(this IDataReader dr, string fieldName)
{
    object value = dr[fieldName];

    Type t = typeof(T);
    t = Nullable.GetUnderlyingType(t) ?? t;

    return (value == null || DBNull.Value.Equals(value)) ? 
        default(T) : (T)Convert.ChangeType(value, t);
}

ব্যবহার করে কল করা:

string field1 = dr.GetValue<string>("field1");
int? field2 = dr.GetValue<int?>("field2");
DateTime field3 = dr.GetValue<DateTime>("field3");

আমি http://www.endswithsaurus.com/2010_07_01_archive.html এ সহ ব্লগ পোস্টগুলির একটি সিরিজ লিখেছি ( সংযোজনে নীচে স্ক্রোল করুন , @ জনম্যাসিন্টায়ার আসলে আমার বাগের কোডটিতে বাগটি খুঁজে পেয়েছিল যা আপনাকে ঠিক একই পথে নিয়ে গেছে you 're এখনই). সেই পোস্টের পরে আমার বেশ কয়েকটি ছোট ছোট পরিবর্তন হয়েছে যার মধ্যে এনাম ধরণের রূপান্তর অন্তর্ভুক্ত রয়েছে তাই আপনার সম্পত্তি যদি এনুম হয় তবে আপনি একই পদ্ধতি কলটি ব্যবহার করতে পারেন। এনামের প্রকারগুলি পরীক্ষা করার জন্য কেবল একটি লাইন যুক্ত করুন এবং আপনি এই জাতীয় কিছু ব্যবহার করে দৌড়ে আসবেন:

if (t.IsEnum)
    return (T)Enum.Parse(t, value);

সাধারণত আপনার পার্সের পরিবর্তে ট্রাই পার্সে চেক করতে বা ব্যবহার করতে কিছু ত্রুটি হয়েছিল তবে আপনি ছবিটি পেয়ে যান।


ধন্যবাদ - আমি এখনও একটি পদক্ষেপ মিস করছি বা কিছু বুঝতে পারছি না। আমি একটি সম্পত্তি মান সেট করার চেষ্টা করছি, আমি কেন এটির অন্তর্নিহিত ধরণের জিনিসটি পাচ্ছি? আমি আমার কোড থেকে আপনার মতো কোনও এক্সটেনশন পদ্ধতিতে কীভাবে যাব সে সম্পর্কেও আমি নিশ্চিত নই। মানটির মতো কিছু করার জন্য টাইপটি কী হবে তা আমি জানব না el সহায়তা <<< 32>>)।
ইবোইনো

@ আইবোয়েনো - দুঃখিত, একটি সভায় বন্ধ ছিল তাই আপনাকে বিন্দুগুলি সংযোগ করতে সাহায্য করতে পারছিলাম না। খুশী হলেও আপনি একটি সমাধান পেয়েছেন।
বেনএলাবাস্টার

9

এটি একটি উদাহরণের জন্য সামান্য দীর্ঘ-ইশ, তবে এটি তুলনামূলকভাবে দৃ approach় পদ্ধতির এবং অজানা মান থেকে অজানা প্রকারে কাস্টিংয়ের কাজটিকে পৃথক করে

আমার কাছে ট্রাইকাস্ট পদ্ধতি রয়েছে যা একই রকম কিছু করে, এবং বিবেচনামূলক ধরণের অ্যাকাউন্টগুলিতে নেয়।

public static bool TryCast<T>(this object value, out T result)
{
    var type = typeof (T);

    // If the type is nullable and the result should be null, set a null value.
    if (type.IsNullable() && (value == null || value == DBNull.Value))
    {
        result = default(T);
        return true;
    }

    // Convert.ChangeType fails on Nullable<T> types.  We want to try to cast to the underlying type anyway.
    var underlyingType = Nullable.GetUnderlyingType(type) ?? type;

    try
    {
        // Just one edge case you might want to handle.
        if (underlyingType == typeof(Guid))
        {
            if (value is string)
            {
                value = new Guid(value as string);
            }
            if (value is byte[])
            {
                value = new Guid(value as byte[]);
            }

            result = (T)Convert.ChangeType(value, underlyingType);
            return true;
        }

        result = (T)Convert.ChangeType(value, underlyingType);
        return true;
    }
    catch (Exception ex)
    {
        result = default(T);
        return false;
    }
}

অবশ্যই ট্রাই কাস্ট একটি টাইপ প্যারামিটার সহ একটি পদ্ধতি, তাই এটিকে গতিশীল বলার জন্য আপনাকে নিজেই মেথডইনফোটি তৈরি করতে হবে:

var constructedMethod = typeof (ObjectExtensions)
    .GetMethod("TryCast")
    .MakeGenericMethod(property.PropertyType);

তারপরে প্রকৃত সম্পত্তি মান সেট করতে:

public static void SetCastedValue<T>(this PropertyInfo property, T instance, object value)
{
    if (property.DeclaringType != typeof(T))
    {
        throw new ArgumentException("property's declaring type must be equal to typeof(T).");
    }

    var constructedMethod = typeof (ObjectExtensions)
        .GetMethod("TryCast")
        .MakeGenericMethod(property.PropertyType);

    object valueToSet = null;
    var parameters = new[] {value, null};
    var tryCastSucceeded = Convert.ToBoolean(constructedMethod.Invoke(null, parameters));
    if (tryCastSucceeded)
    {
        valueToSet = parameters[1];
    }

    if (!property.CanAssignValue(valueToSet))
    {
        return;
    }
    property.SetValue(instance, valueToSet, null);
}

এবং সম্পত্তি.CanAssignValue মোকাবেলা করার জন্য এক্সটেনশন পদ্ধতিগুলি ...

public static bool CanAssignValue(this PropertyInfo p, object value)
{
    return value == null ? p.IsNullable() : p.PropertyType.IsInstanceOfType(value);
}

public static bool IsNullable(this PropertyInfo p)
{
    return p.PropertyType.IsNullable();
}

public static bool IsNullable(this Type t)
{
    return !t.IsValueType || Nullable.GetUnderlyingType(t) != null;
}

6

আমারও একইরকম প্রয়োজন ছিল এবং লুক এইচ-এর উত্তর আমাকে দিক নির্দেশ করে। এটি সহজ করার জন্য আমি এই জেনেরিক ফাংশনটি নিয়ে এসেছি।

    public static Tout CopyValue<Tin, Tout>(Tin from, Tout toPrototype)
    {
        Type underlyingT = Nullable.GetUnderlyingType(typeof(Tout));
        if (underlyingT == null)
        { return (Tout)Convert.ChangeType(from, typeof(Tout)); }
        else
        { return (Tout)Convert.ChangeType(from, underlyingT); }
    }

ব্যবহার এই রকম:

        NotNullableDateProperty = CopyValue(NullableDateProperty, NotNullableDateProperty);

নোট করুন যে দ্বিতীয় প্যারামিটারটি কীভাবে রিটার্ন মানটি কাস্ট করা যায় তা ফাংশনটি প্রদর্শন করতে প্রোটোটাইপ হিসাবে ব্যবহৃত হয়, সুতরাং এটি আসলে গন্তব্য সম্পত্তি হতে হবে না। মানে আপনি এর মতো কিছু করতে পারেন:

        DateTime? source = new DateTime(2015, 1, 1);
        var dest = CopyValue(source, (string)null);

আমি এটি আউট ব্যবহার করার পরিবর্তে এইভাবে করেছি কারণ আপনি বৈশিষ্ট্যগুলি ব্যবহার করতে পারবেন না। যেমনটি, এটি বৈশিষ্ট্য এবং ভেরিয়েবলগুলির সাথে কাজ করতে পারে। আপনি চাইলে পরিবর্তে টাইপটি পাস করার জন্য একটি ওভারলোডও তৈরি করতে পারেন।


0

ধন্যবাদ @ লুকেহ
আমি একটু বদলে গেলাম:

public static object convertToPropType(PropertyInfo property, object value)
{
    object cstVal = null;
    if (property != null)
    {
        Type propType = Nullable.GetUnderlyingType(property.PropertyType);
        bool isNullable = (propType != null);
        if (!isNullable) { propType = property.PropertyType; }
        bool canAttrib = (value != null || isNullable);
        if (!canAttrib) { throw new Exception("Cant attrib null on non nullable. "); }
        cstVal = (value == null || Convert.IsDBNull(value)) ? null : Convert.ChangeType(value, propType);
    }
    return cstVal;
}

0

আমি এইভাবে এটি করেছি

public static List<T> Convert<T>(this ExcelWorksheet worksheet) where T : new()
    {
        var result = new List<T>();
        int colCount = worksheet.Dimension.End.Column;  //get Column Count
        int rowCount = worksheet.Dimension.End.Row;

        for (int row = 2; row <= rowCount; row++)
        {
            var obj = new T();
            for (int col = 1; col <= colCount; col++)
            {

                var value = worksheet.Cells[row, col].Value?.ToString();
                PropertyInfo propertyInfo = obj.GetType().GetProperty(worksheet.Cells[1, col].Text);
                propertyInfo.SetValue(obj, Convert.ChangeType(value, Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType), null);

            }
            result.Add(obj);
        }

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