我从存储过程中获取运行时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
。请参阅以下图片,其中包含以下列:
https://docs.python.org/3.6/library/re.html#re.findall
我可以在运行时了解列名和列数。
是否可以在运行时创建一个具有上述列作为属性的类,并像往常一样将它们投影到这些属性:
public IQueryable<EmployeeDTO> GetEmployees()
{
return db.Employees
.Select(employee => new EmployeeDTO
{
ID = employee.ID,
FirstName = employee.PriceNumber,
LastName = employee.PriceDate
}).AsQueryable();
}
所以我的目标是创建具有DataTable
和项目DataTable
列的属性的类到具有属性的类。
是否可以在运行时创建属性并将DataTable
列投影到新创建的类属性?
答案 0 :(得分:3)
动态构成班级形状的一种方法是使用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;
}
}
我们在这里:
items
字典。允许我们存储任何值并按名称获取。TryGetMember()/TrySetMember()
方法。该群组允许我们使用Dot-Property
表示法设置/获取值:Class.Property
。TrySetIndex()/TryGetIndex()
方法。该群组允许我们使用Indexer
表示法设置/获取值:Class[varHoldingPropName]
或Class["propName"]
。GetDynamicMemberNames()
方法。允许检索所有属性名称。要设置属性名称,您必须使用Indexer
表示法,因为使用Dot-Property
表示法时,活页夹将使用您的属性名称作为标识符名称,而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"]);
}
应用程序的逻辑如下:您可以获取列&#39;来自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
}