值类型的通用初始化 [英] Generic initialization of value types

查看:68
本文介绍了值类型的通用初始化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,

我一直在与这个问题作斗争一段时间,找不到解决方案.请帮忙!

我想做的是使用泛型从数据集中动态提取对象列表.当您尝试初始化int/decimal/double时,它会发挥作用,而落在那儿.因为默认值为0,所以可以将其解释为任何一种数字类型.当我运行此命令并尝试初始化一个int时,编译器将其识别为十进制并引发异常.我已经尝试了许多解决方法,包括使用item.PropertyType.TypeInitializer.Invoke(null);. TypeInitializer为null :-(同样,在PropertyType上使用.GetConstructor()方法也不会产生任何结果.我也尝试使用default(),但它不接受Type作为初始化程序.尝试找出这个头发...

我相信问题在于使用对象作为传递给ConvertDBNull<>()方法的Type.由于无法通过PropertyType作为通用参数发送,因此不确定如何解决此问题.

代码如下:

Hey all,

I''ve been battling with this issue for some time and can''t find a solution. Please help!

What I''m trying to do is dynamically extract a list of objects from a dataset using generics. It works up to a point and where it falls over is when you try and initialize an int / decimal / double. Because the default value is 0, this can be interpreted as either of the numeric types. When I run this and try to initialize an int, the compiler recognises it as a decimal and throws an exception. I''ve tried a number of work arounds including using the item.PropertyType.TypeInitializer.Invoke(null); The TypeInitializer is null :-( Along the same lines using the .GetConstructor() method on the PropertyType also yields no results. I''ve also tried to use default() but it does not accept the Type as an initializer. Pulling my hair out trying to figure this one out...

I believe the problem is using object as the Type passed to the ConvertDBNull<>() method. Not sure how to get around this as you cannot send through the PropertyType as a generic parameter.

The code is below:

<br />
<pre lang="cs">/// <summary><br />
        /// Checks if the value passed in is null. If it is, it returns the replacement value<br />
        /// else it will convert the object value in the specified type<br />
        /// </summary><br />
        /// <typeparam name="T">Type of object to be returned</typeparam><br />
        /// <param name="value">Value to be checked and converted</param><br />
        /// <param name="replacement">Replacement value in case of null</param><br />
        /// <returns>Value as specified type or replacement value if the object is null</returns><br />
        public static T ConvertDBNull<T>(object value, T replacement)<br />
        {<br />
            if ((value == null) || (value == DBNull.Value))<br />
                return replacement;<br />
            else<br />
                return (T)Convert.ChangeType(value, typeof(T));<br />
        }<br />
<br />
        public static object InitializeProperty(Type propertyType)<br />
        {<br />
            if (propertyType == typeof(string))<br />
                return string.Empty;<br />
            else if ((propertyType == typeof(int)) || (propertyType == typeof(long)))<br />
                return int.Parse("0");<br />
            else if (propertyType == typeof(DateTime))<br />
                return DateTime.MinValue;<br />
            else if (propertyType == typeof(char))<br />
                return char.MinValue;<br />
            else if (propertyType == typeof(bool))<br />
                return false;<br />
            else if (propertyType == typeof(Guid))<br />
                return new Guid();<br />
            else if (propertyType == typeof(decimal))<br />
                return decimal.Parse("0");<br />
            else if (propertyType == typeof(double))<br />
                return double.Parse("0");<br />
            else if (propertyType.IsGenericType &&<br />
                propertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))<br />
                return null;<br />
<br />
            return new object();<br />
        }<br />
<br />
        public static List<DataObj> ExtractObjectsFromDataSet<DataObj>(DataSet dsValues)<br />
        {<br />
            var workingItem = (DataObj)Activator.CreateInstance(typeof(DataObj));<br />
            List<DataObj> result = new List<DataObj>();<br />
            List<PropertyInfo> props = new List<PropertyInfo>(typeof(DataObj).GetProperties());<br />
<br />
            foreach (DataRow row in dsValues.Tables[0].Rows)<br />
            {<br />
                workingItem = (DataObj)Activator.CreateInstance(typeof(DataObj));<br />
<br />
                foreach (PropertyInfo item in props)<br />
                {<br />
                    if (dsValues.Tables[0].Columns.Contains(item.Name))<br />
                    {<br />
                        if ((row[item.Name] != DBNull.Value) && (row[item.Name] != null))<br />
                        {<br />
                            var tmpValue = Activator.CreateInstance(item.PropertyType);<br />
                            item.SetValue(workingItem, ConvertDBNull<object>(row[item.Name], InitializeProperty(item.PropertyType)), null);<br />
                        }<br />
                    }<br />
                }<br />
<br />
                result.Add(workingItem);<br />
            }<br />
<br />
            return result;<br />
        }</pre><br />
<br />


更改了< pre>的lang属性;来自xml的标记-> c#


Changed lang attribute of <pre> tag from xml -> c#

推荐答案

在我看来,您遇到的问题是您的DataRow持有Int32,并且您想将其分配给Decimal使用PropertyInfoSetValue方法.

为此,您只需要使用Convert.ChangeType方法,它将为您处理转换.
像在此示例应用程序中一样(为简单起见,我删除了DataRowDbNull s,但问题是相同的):

It looks to me that the problem you''re running into is your DataRow holding an Int32 and you want to assign that to a Decimal using the SetValue method of PropertyInfo.

To do that you only need to use the Convert.ChangeType method, it''ll handle the cast for you.
Like in this example application (i''ve stripped DataRows and DbNulls out for simplicity, but the problem is the same):

using System;
using System.Collections.Generic;
using System.Reflection;

namespace ConsoleApplication14
{
    public class MyObject
    {
        public int Int { get; set; }
        public double Double { get; set; }
        public float Float { get; set; }
        public decimal Decimal { get; set; }
        public string String { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // Pretend that this is your data row;
            IDictionary<string, object> values = new Dictionary<string, object>();

            values["Int"] = 1;
            values["Double"] = 123.0f;
            values["Float"] = 120.0d;
            values["Decimal"] = 2;
            values["String"] = "0";

            MyObject o = new MyObject();
            foreach (string name in values.Keys)
            {
                PropertyInfo property = o.GetType().GetProperty(name);

                // This will fail because the 2 assigned to "Decimal" 
                // is in fact an Int32
                //property.SetValue(o, values[name], null);

                // This should work
                property.SetValue(o, Convert.ChangeType(values[name], 
                                  property.PropertyType), null);
            }
        }
    }
}



希望这会有所帮助,
弗雷德里克(Fredrik)



Hope this helps,
Fredrik


这篇关于值类型的通用初始化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆