【问题标题】:C# : Create a Tuple from a generic type using reflectionC#:使用反射从泛型类型创建元组
【发布时间】:2017-11-22 10:56:03
【问题描述】:

我希望能够将元组传递给以下方法,但我不能,因为我必须实例化它。

    public List<T> Select<T>(string sql, DbCommand command) where T : new()
    {
        DbDataReader dataReader = null;
        List<T> ls = new List<T>();
        Type tType = typeof(T);
        T t;
        PropertyInfo prop = null;
        string[] propertiesNames = GetPropertiesNamesFromSQL(sql);

        try
        {
            dataReader = command.ExecuteReader();
            if (dataReader == null || !dataReader.HasRows) return ls;

            while (dataReader.Read())
            {
                t = new T();

                for (int i = 0; i < dataReader.FieldCount; i++)
                {
                    prop = tType.GetProperty(propertiesNames[i]);

                    prop.SetValue(t, dataReader.GetValue(i));
                }

                ls.Add(t);
            }
        }
        catch (Exception){  }
        finally
        {
            if (dataReader != null) dataReader.Close();
        }

        return ls;
    }

正如我在 cmets 中所说,我正在尝试构建一个裸骨 ORM,我只对映射到对象部分感兴趣。它按原样工作,但有时快速查询能够传递一个元组而不是一个完整的类是很实用的。

有什么解决办法吗?

【问题讨论】:

  • 不确定我是否理解...为什么不能将元组作为参数传递?
  • 为确保这不是 XY 问题 (meta.stackexchange.com/questions/66377/what-is-the-xy-problem),您能否退一步解释一下为什么需要此代码?
  • 当您说传递元组时,您是在询问是否将其用作通用参数?你不能作为一个元组做的是一个结构而不是一个类。使用内部代码也没有意义,因为元组没有名为“ClientName”的属性。除非您在谈论 TupleClass(老实说我没有调查过)
  • 我正在构建一个简单的 ORM(我只对映射到对象部分感兴趣,我仍然会编写我的 sql 查询),有时对于快速查询,通过一个元组而不是创建一个完整的类。 @Ruslan 元组没有空的默认构造函数,所以 T t = new T();如果 T 是元组会抛出异常。
  • 可能,是的。容易,不。您需要删除new 约束,检查T 是否为TupleValueTuple 或其他,并通过反射调用适当的构造函数。请注意,元组仅对非常小的结果集真正有用,因为元组成员具有不利于轻松访问的通用名称(并且ValueTuple 的名称映射依赖于您的成员中不可用的编译时信息)。您真的不想阅读 Item7 是客户名称的代码。事实上,我什至会说元组支持在 ORM 中是不值得的。

标签: c# generics reflection tuples


【解决方案1】:

这种方式是行不通的。创建一个可以从数据库生成任何东西的方法并不是一个好的解决方案,原因有很多。

执行此操作的正确方法会稍微复杂一些。我认为您需要一个工厂接口,如下所示:

public interface IMyFactory<T> where T : new() 
{ 
    T Create ( string name ); 
}

然后是混凝土工厂:

public class MyFactory : IMyFactory<MyClient>
{
    public MyClient Create ( string name )
    {
        var t = new MyClient();
        t.ClientName = name;
        return t;
    }
}

然后将其传递给您的方法,例如:

public List<T> SelectFromDataBase<T> ( IMyFactory<T> factory ) where T : new()
{
    var ls = new List<T>();

    // highly simplified here
    T t = factory.Create("Mr Smith");

    ls.Add(t);

    return ls;        
}

然后您可以将您的方法称为:

var myList = SelectFromDataBase(new MyFactory());

这样,您可以不断地将数据库中的数据转换为与对象创建逻辑分离的对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多