简体   繁体   English

如何在C#中将[TYPE]转换为可为空的<[TYPE]>?

[英]How to convert [TYPE] to nullable<[TYPE]> in C#?

Question: 题:

I wrote a method to retrieve a SQL result as a list of a class instead of a datatable. 我编写了一个方法来检索SQL结果作为类的列表而不是数据表。 The problem is, I have a int field in the database, which is nullable. 问题是,我在数据库中有一个可以为空的int字段。

If I hit a row with a NULL int , DataReader returns DbNull.Value instead of null. 如果我用NULL int命中一行, DataReader将返回DbNull.Value而不是null。 So System.Convert.ChangeType(objVal, fi.FieldType) throws an exception, because it can't convert DbNull to an int . 所以System.Convert.ChangeType(objVal, fi.FieldType)抛出异常,因为它无法将DbNull转换为int

So far so bad. 到目前为止这么糟糕。 I thought I had solved the problem, when I just compared objVal to DbNull.Value and if true, did this instead: System.Convert.ChangeType(null, fi.FieldType) 我以为我已经解决了这个问题,当我只是将objValobjVal进行DbNull.Value ,如果是,则执行此操作: System.Convert.ChangeType(null, fi.FieldType)

unfortunately, I just realized, the resulting integer type is 0 instead of NULL. 不幸的是,我刚刚意识到,结果整数类型是0而不是NULL。

So I just tried changing the int type in my class to Nullable<int> , but now I have the problem that when a value is not DbNull.Value , ChangeType throws an exception because it can't convert int to nullable<int> ... 所以我只是尝试将我的类中的int类型更改为Nullable<int> ,但现在我遇到的问题是,当值不是DbNull.ValueChangeType会抛出异常,因为它无法将int转换为nullable<int> 。 ..

So now I try to detect the type of the object returned by datareader , and convert it to a nullable value. 所以现在我尝试检测datareader返回的对象的类型,并将其转换为可空值。

tTypeForNullable is correctly shown as Nullable<int> . tTypeForNullable正确显示为Nullable<int> But when I look at the result type, I get: int . 但是当我查看结果类型时,我得到: int

Why is that ? 这是为什么 ? And more important: How can I do that properly ? 更重要的是:我该如何正确地做到这一点?

Please note that because type is an object, I can't use a generic method to create Nullable<int> . 请注意,因为type是一个对象,所以我不能使用泛型方法来创建Nullable<int>

bool bisnull = IsNullable(objVal);
bool bisnullt = IsNullable(fi.FieldType);

if (bisnullt)
{
    Type tTypeForNullable = typeof(Nullable<>).MakeGenericType(objVal.GetType());

    //object result = Activator.CreateInstance(tTypeForNullable, new object[] { objVal });
    //object result = Activator.CreateInstance(typeof(Nullable<int>), new object[] { objVal });
    object result = Activator.CreateInstance(tTypeForNullable, objVal);
    Type tres = result.GetType();
    fi.SetValue(tThisValue, System.Convert.ChangeType(result, fi.FieldType));
}

Here's the complete routine for reference: 这是完整的例行程序供参考:

public virtual System.Collections.Generic.IList<T> GetList<T>(System.Data.IDbCommand cmd)
        {
            System.Collections.Generic.List<T> lsReturnValue = new System.Collections.Generic.List<T>();
            T tThisValue = default(T);
            Type t = typeof(T);

            lock (cmd)
            {
                using (System.Data.IDataReader idr = ExecuteReader(cmd))
                {

                    lock (idr)
                    {

                        while (idr.Read())
                        {
                            //idr.GetOrdinal("")
                            tThisValue = Activator.CreateInstance<T>();

                            // Console.WriteLine(idr.FieldCount);
                            for (int i = 0; i < idr.FieldCount; ++i)
                            {
                                string strName = idr.GetName(i);
                                object objVal = idr.GetValue(i);


                                System.Reflection.FieldInfo fi = t.GetField(strName);
                                //Type tttttt = fi.FieldType;
                                if (fi != null)
                                {
                                    //fi.SetValue(tThisValue, System.Convert.ChangeType(objVal, fi.FieldType));
                                    if (objVal == System.DBNull.Value)
                                    {
                                        objVal = null;
                                        fi.SetValue(tThisValue, null);
                                    }
                                    else
                                    {
                                        //System.ComponentModel.TypeConverter conv = System.ComponentModel.TypeDescriptor.GetConverter(fi.FieldType);

                                        bool bisnull = IsNullable(objVal);
                                        bool bisnullt = IsNullable(fi.FieldType);

                                        if (bisnullt)
                                        {
                                            Type tTypeForNullable = typeof(Nullable<>).MakeGenericType(objVal.GetType());

                                            //object result = Activator.CreateInstance(tTypeForNullable, new object[] { objVal });
                                            //object result = Activator.CreateInstance(typeof(Nullable<int>), new object[] { objVal });
                                            object result = Activator.CreateInstance(tTypeForNullable, objVal);
                                            Type tres = result.GetType();
                                            fi.SetValue(tThisValue, System.Convert.ChangeType(result, fi.FieldType));
                                        }
                                        fi.SetValue(tThisValue, System.Convert.ChangeType(objVal, fi.FieldType));
                                    }
                                }
                                else
                                {
                                    System.Reflection.PropertyInfo pi = t.GetProperty(strName);
                                    if (pi != null)
                                    {
                                        //pi.SetValue(tThisValue, System.Convert.ChangeType(objVal, pi.PropertyType), null);


                                        if (objVal == System.DBNull.Value)
                                        {
                                            objVal = null;
                                            pi.SetValue(tThisValue, null, null);
                                        }
                                        else
                                        {
                                            pi.SetValue(tThisValue, System.Convert.ChangeType(objVal, pi.PropertyType), null);
                                        }


                                    }
                                    // Else silently ignore value
                                } // End else of if (fi != null)

                                //Console.WriteLine(strName);
                            } // Next i

                            lsReturnValue.Add(tThisValue);
                        } // Whend

                        idr.Close();
                    } // End Lock idr

                } // End Using idr

            } // End lock cmd

            return lsReturnValue;
        } // End Function GetList

with this: 有了这个:

public System.Data.IDataReader ExecuteReader(System.Data.IDbCommand cmd)
        {
            System.Data.IDataReader idr = null;

            lock(cmd)
            {
                System.Data.IDbConnection idbc = GetConnection();
                cmd.Connection = idbc;

                if (cmd.Connection.State != System.Data.ConnectionState.Open)
                    cmd.Connection.Open();

                idr = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
            } // End Lock cmd

            return idr;
        } // End Function ExecuteReader

Please note that because type is an object, I can't use a generic method to create Nullable<int> . 请注意,因为type是一个对象,所以我不能使用泛型方法来创建Nullable<int>

You're boxing - and the result of a boxing operation for a nullable value type is never a boxed value of that type. 你正在装箱 - 对于可以为空的值类型的装箱操作的结果永远不是该类型的盒装值。 It's either null or a non-nullable value type. 它是null或非可空值类型。 See MSDN for more information. 有关更多信息,请参阅MSDN

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM