创建类的属性并在运行时对其进行投影 [英] Create properties of class and project to them at the runtime

查看:147
本文介绍了创建类的属性并在运行时对其进行投影的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在运行时从存储过程中从DataTable获取列.代码如下:

I am getting columns from the DataTable at the runtime from the stored procedure. Code looks like this:

var parkDataTable = new DataTable("tmp");
...
SqlCommand cmd = new SqlCommand("FooStoredProcedure", db.Database.Connection as 
    SqlConnection, transaction.UnderlyingTransaction as SqlTransaction);
cmd.CommandType = CommandType.StoredProcedure;    
dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
parkDataTable.Load(dr);

有趣的是,通过在列名称中添加日期,我的列可以具有各种名称.例如,我有一个列名称2017-09-01_FactPark,那么下一次它可以是2017-10-01_FactPark.请,请参见带有列的下图:

The interesting thing that my columns can have various names by adding date to a column name. For example, I have a column name 2017-09-01_FactPark, then the next time it can be 2017-10-01_FactPark. Please, see the following image with the columns:

我可以在运行时就知道列名和列数.

是否可以在运行时使用上述列作为属性来创建一个类,并将它们投影为这些属性,就像通常的方式一样:

Is it possible to create a class with the above columns as properties at the runtime and project them to these properties like usual way:

public IQueryable<EmployeeDTO> GetEmployees()
{
    return db.Employees
        .Select(employee => new EmployeeDTO
        {
            ID = employee.ID,                    
            FirstName = employee.PriceNumber,
            LastName = employee.PriceDate                                        
        }).AsQueryable();
}

所以我的目标是创建具有属性的类,从DataTable并将项目DataTable列投影到具有属性的类.

So my goal is to create class with properties from the DataTable and project DataTable columns to the class with properties.

是否可以在运行时创建属性并将DataTable列投影到新创建的类属性?

Is it possible to create properties at the runtime and project DataTable columns to newly created properties of class?

推荐答案

动态构造类形状的一种方法是使用DynamicObject类.您可以创建自己的动态类,该类将设置和获取其值的属性.

One way to dynamically constitute the shape of your class is with DynamicObject class. You can create your own dynamic class which would set and fetch properties with their values.

现在,让我们实现动态类:

For now, let's implement our dynamic class:

using System.Dynamic;

class Dynamo : DynamicObject
{
    private Dictionary<string, object> items = new Dictionary<string, object>();

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        return items.TryGetValue(binder.Name, out result);
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        items[binder.Name] = value;
        return true;
    }

    public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
    {
        string propName = indexes[0] as string;
        items[propName] = value;
        return true;
    }

    public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
    {
        string propName = indexes[0] as string;
        return items.TryGetValue(propName, out result);
    }

    public override IEnumerable<string> GetDynamicMemberNames()
    {
        return items.Keys;
    }
}

我们在这里拥有什么

  1. items字典.允许我们存储任何值并按其名称获取.
  2. TryGetMember()/TrySetMember()方法.该组允许我们使用Dot-Property表示法设置/获取值:Class.Property.
  3. TrySetIndex()/TryGetIndex()方法.该组允许我们使用Indexer表示法设置/获取值:Class[varHoldingPropName]Class["propName"].
  4. GetDynamicMemberNames()方法.允许检索所有属性名称.
  1. items dictionary. Allows us to store any value and fetch it by its name.
  2. TryGetMember()/TrySetMember() methods. This group allows us to set/fetch values with Dot-Property notation: Class.Property.
  3. TrySetIndex()/TryGetIndex() methods. This group allows us to set/fetch values with Indexer notation: Class[varHoldingPropName] or Class["propName"].
  4. GetDynamicMemberNames() method. Allows to retrieve all properties names.

要设置属性名称,必须使用Indexer表示法,因为使用Dot-Property表示法,活页夹将使用您的属性名称作为标识符名称,而Indexer会评估您的变量:

In order to set property names, you must use Indexer notation, because with Dot-Property notation the binder will use your property name as identifier name, while Indexer will evaluate your variable:

static void UseDynamicObject()
{

    var colorProperty = "Color";
    var ageProperty = "Age";

    dynamic dynamo = new Dynamo();
    dynamo.colorProperty = "red";
    dynamo[ageProperty] = 20;

    // DOT-PROPERTY NOTATION
    // Error: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:
    // 'Dynamo' does not contain a definition for 'Color'.
    Console.WriteLine(dynamo.Color);
    // The property used to retrieve value "red" is "colorProperty" rather "Color".
    Console.WriteLine(dynamo.colorProperty);

    // INDEXER NOTATION
    // We can use either variable or literal name of the property,
    // so these two lines are equivalent.
    Console.WriteLine(dynamo[ageProperty]);
    Console.WriteLine(dynamo["Age"]);

}

应用的逻辑如下:您可以从SqlDataReader获取列名,并将其用于在动态对象上进行设置.

The logic for app is following: you could fetch columns' names from SqlDataReader and use them for setting them on your dynamic object.

这是使用SqlDataReader和我们的动态类的一种可能的变体:

Here's one possible variant of using SqlDataReader and our dynamic class:

static void Main(string[] args)
{

    var data = new List<dynamic>();
    List<string> cols = default;

    using (var conn = new SqlConnection(connStr))
    {
        conn.Open();
        using (var comm = new SqlCommand("SELECT * FROM dbo.Client", conn))
        {
            using (var reader = comm.ExecuteReader())
            {
                // Get columns names
                cols = Enumerable.Range(0, reader.FieldCount)
                       .Select(i => reader.GetName(i)).ToList();
                while (reader.Read())
                {
                    dynamic obj = new Dynamo();
                    cols.ForEach(c => obj[c] = reader[c]);
                    data.Add(obj);
                }
            }
        }
    }


    /* OUTPUT DATA */

    // To get columns names, you can:
    // 1) use ready "cols" variable
    // 2) use "GetDynamicMemberNames()" on first object:
    //    IEnumerable<string> cols = data[0].GetDynamicMemberNames();
    foreach (var obj in data)
    {
        Console.WriteLine(String.Join(", ", cols.Select(c => $"{c} = {obj[c]}")));
    }

    // Output:
    // ClientId = 1, ClientName = Client1
    // ClientId = 2, ClientName = Client2

}

这篇关于创建类的属性并在运行时对其进行投影的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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