【问题标题】:Convert Array to Type Array将数组转换为类型数组
【发布时间】:2013-05-01 03:19:38
【问题描述】:

我正在从数据库数据创建一个通用对象:

object[] data = new object[dataReader.FieldCount];
dataReader.GetValues(data);
T t = (T)Activator.CreateInstance(typeof(T), data);

但是,第三行没有构造函数错误的类型。我想加一个if

if (typeof(T).GetConstructor(data.TypesOf()) != null)

data.TypesOf() 实际上是一个数组 - Type[] - 包含data 中所有类型的对象。

真正有效的data.TypesOf() 是什么?

或者我需要迭代 data 并自己构建它?

【问题讨论】:

  • data 始终是 object[] - 它与 typeof(T) 没有任何关系,因为它只是来自读者的值。你想用data.TypesOf() 代表什么?
  • @MarcGravell。 data.TypesOf() 是一个 Type[] 数组,其中包含 data 的类型。按顺序,在那。已添加到问题中。

标签: c# arrays types


【解决方案1】:

【讨论】:

    【解决方案2】:

    当您查看Activator.CreateInstance(Type, Object[]) 方法时,对于Object[] 参数:

    在数量、顺序和类型上匹配的参数数组 要调用的构造函数的参数。如果 args 是一个空数组或 null,不带参数的构造函数(默认 构造函数)被调用。

    所以也许在您的情况下,您的 data 对象没有为每个值键入(如果从数据库或文件中获取)。您需要找到一种方法在 data 数组中“键入”您的对象。

    【讨论】:

    • @JNF 你确定吗?特别是,不匹配在single/double/decimalshort/int/long 之间很常见(我从我的微 ORM 工作中充满信心地说)。我强烈建议先看看Array.ConvertAll(data, x => x.GetType()) 所说的内容,然后再大胆地说“不。类型没问题。”。如果类型没问题,Activator 应该已经找到了构造函数。
    • @MarcGravell - 当然。我检查了我的数据。还没有遇到您描述的问题,所以这不是这里的问题。会的,也许还有一次。 :)
    • @JNF 在这种情况下:构造函数是非公开的吗?简而言之,它要么是数据不匹配,要么是非公共构造函数。
    • @MarcGravell,为了让它更清楚 - 有时我会明确地将该函数用于没有构造函数的类型。说int
    • @JNF then...为什么你的代码正在寻找构造函数?另外:dapper 的 Query<int>(sql, args) 会处理得很好
    【解决方案3】:

    据我了解,您正在尝试获取对象数组的元素类型。所以你可以这样做:

     var ctorArgsTypes = data.Select(d => d.GetType()).ToArray()
    
     var ctor = typeof(T).GetConstructor(ctorArgsType);
    
     // check if appropriate ctor exists
     if (ctor == null)
         throw something
    
     T t = (T)Activator.CreateInstance(typeof(T), data);
    

    【讨论】:

    • 对。我试图弄清楚是否存在内置方法,而不是调用 LINQ 查询。
    【解决方案4】:

    我假设您的object[] 包含的值例如是intstringfloat,并且您正在尝试解析public T(int,string,float) 形式的构造函数。要获取类型,您可以使用:

    var types = Array.ConvertAll(data, x => x.GetType());
    

    但这实际上对你没有多大帮助,因为这几乎是 Activator.CreateInstance(typeof(T), data) 已经尝试做的事情 - 所以如果 Activator 失败了,我看不到很明显,你会做得更好——除非关键区别在于构造函数是非公开的并且你将提供一些BindingFlags

    不过,我个人建议按name 绑定比按位置绑定更容易;有像dapper 这样的工具可以为你完成所有这些,让你可以简单地使用:

    var data = conn.Query<SomeType>(sql, args).ToList();
    

    例如:

    int userId = 12345;
    var users = conn.Query<User>("select * from Users where Id = @userId",
          new {userId}).SingleOrDefault();
    

    【讨论】:

    • 感谢您的工具。我实际上是在尝试避免使用 ORM,因为我了解它会降低性能和数据库负载。我想听听你对此的立场,虽然因为它离题了所以不在这里。
    • @JNF 我不认为这是题外话——你的担忧是合理的,但没有根据。实际上,我们编写 dapper 是为了避免 ORM 的所有性能问题——它是一个微 ORM,而不是完整的 ORM。它除了 materialization(将行数据转换为对象)之外没有做任何其他事情,并且它残酷地高效地做到了(它在内部使用原始 IL 生成,它缓存( IL)等)。我们对其进行了广泛的分析:它与手动编写IDataReader 代码的速度基本相同,但没有人为错误。
    • @JNF 但是是的,在一般情况下,ORM 可能会很慢 - 实体框架和 NHibernate 尤其具有很多复杂性和开销(尽管我已经看到了两者团队最近试图提高性能)。不过,微 ORM 只是处于完全不同的性能领域。
    猜你喜欢
    • 2011-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-13
    • 2021-09-09
    • 2017-05-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多