gpt4 book ai didi

c# - 在运行时创建类和项目的属性

转载 作者:太空宇宙 更新时间:2023-11-03 22:49:39 25 4
gpt4 key购买 nike

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

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。请查看下图的列:

enter image description here

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

是否可以在运行时创建一个将上述列作为属性的类,并像往常一样将它们投影到这些属性:

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

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

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

最佳答案

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

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

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() 方法。允许检索所有属性名称。

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

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 获取列的名称,并使用它们在您的动态对象上进行设置。

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

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

}

关于c# - 在运行时创建类和项目的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47966620/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com