动态构成类形状的一种方法是使用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"]);
}
应用程序的逻辑如下:您可以从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
}