创建类的属性并在运行时对其进行投影 [英] Create properties of class and project to them at the runtime
问题描述
我在运行时从存储过程中从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;
}
}
我们在这里拥有什么
-
items
字典.允许我们存储任何值并按其名称获取. -
TryGetMember()/TrySetMember()
方法.该组允许我们使用Dot-Property
表示法设置/获取值:Class.Property
. -
TrySetIndex()/TryGetIndex()
方法.该组允许我们使用Indexer
表示法设置/获取值:Class[varHoldingPropName]
或Class["propName"]
. -
GetDynamicMemberNames()
方法.允许检索所有属性名称.
items
dictionary. Allows us to store any value and fetch it by its name.TryGetMember()/TrySetMember()
methods. This group allows us to set/fetch values withDot-Property
notation:Class.Property
.TrySetIndex()/TryGetIndex()
methods. This group allows us to set/fetch values withIndexer
notation:Class[varHoldingPropName]
orClass["propName"]
.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屋!