在DynamicObject的文档中,有一个DynamicDictionary
的示例,它允许您使用字典,就像它是一个具有属性的类一样。
这是课程(为简洁起见稍作修改):
public class DynamicDictionary : DynamicObject
{
Dictionary<string, object> _dictionary = new Dictionary<string, object>();
public int Count
{
get { return _dictionary.Count; }
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
string name = binder.Name.ToLower();
return _dictionary.TryGetValue(name, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
_dictionary[binder.Name.ToLower()] = value;
return true;
}
}
我想做的是修改课程,以便我可以执行以下操作:
public class Test
{
public Test()
{
var result = Enumerable.Range(1, 5).Select(i => new DynamicDictionary
{
Id = i,
Foo = "Foo",
Bar = 2
});
}
}
问题
答案 0 :(得分:4)
DynamicObject
提供TryCreateInstance()
,适用于此类情况,但无法在C#中使用。
我看到了一些方法:
创建动态工厂类。当您使用命名的参数调用其Create()
方法时,它会将其传递给字典:
class DynamicDictionaryFactory : DynamicObject
{
public override bool TryInvokeMember(
InvokeMemberBinder binder, object[] args, out object result)
{
if (binder.Name == "Create")
{
// use binder.CallInfo.ArgumentNames and args
// to create the dynamic dictionary
result = …;
return true;
}
return base.TryInvokeMember(binder, args, out result);
}
}
…
dynamic factory = new DynamicDictionaryFactory();
dynamic dict = factory.Create(Id: 42);
使用非动态集合初始值设定项。这意味着在代码中将属性名称作为字符串:
// has to implement IEnumerable, so that collection initializer works
class DynamicDictionary
: DynamicObject, IEnumerable<KeyValuePair<string, object>>
{
public void Add(string name, object value)
{
m_dictionary.Add(name, value);
}
// IEnumerable implmentation and actual DynamicDictionary code here
}
…
dynamic dict = new DynamicDictionary { { "Id", 42 } };
可能与您要求的最接近的是使用嵌套对象初始值设定项。也就是说,该类将具有dynamic
属性(例如,Values
),其属性可以使用对象初始值设定项进行设置:
class DynamicDictionary : DynamicObject
{
private readonly IDictionary<string, object> m_expandoObject =
new ExpandoObject();
public dynamic Values
{
get { return m_expandoObject; }
}
// DynamicDictionary implementation that uses m_expandoObject here
}
…
dynamic dict = new DynamicDictionary { Values = { Id = 42 } };
答案 1 :(得分:1)
使用开源ImpromptuInterface(通过nuget)它有一个Builder Syntax。这使你可以做一些接近初始化语法的事情。特别是在包括ImpromptuInterface.Dynamic
之后你可以做
var result = Enumerable.Range(1, 5).Select(i => Build<DynamicDictionary>.NewObject
(
Id: i,
Foo: "Foo",
Bar: 2
));
如果你删除<DynamicDictionary>
,那么语法页面上还会列出其他选项,它将使用ImpromptuDictionary
,这基本上是相同的。您也可以查看source的构建语法。
答案 2 :(得分:0)
事实证明,我能够通过使用Linq的内置ToDictionary()
方法来解决我的问题。
示例:
public Test()
{
var data = Enumerable.Range(1, 5).Select(i => new
{
Id = i,
Foo = "Foo",
Bar = 2
});
var result = data
.Select(d => d.GetType().GetProperties()
.Select(p => new { Name = p.Name, Value = p.GetValue(pd, null) })
.ToDictionary(
pair => pair.Name,
pair => pair.Value == null ? string.Empty : pair.Value.ToString()));
}
答案 3 :(得分:0)
当我看到这样的嵌入式语言模式时,我倾向于使用扩展方法,所以我可以编写以下代码来实现我的目标:
public Test()
{
var data = Enumerable.Range(1, 5).Select(i => new
{
Id = i,
Foo = "Foo",
Bar = 2
}.AsDynamicDictionary());
}
然后我会使用代码定义扩展方法,将任何object
(包括匿名类型的)转换为DynamicDictionary
:
public static class DynamicDictionaryExtensions
{
public static DynamicDictionary AsDynamicDictionary(this object data)
{
if (data == null) throw new ArgumentNullException("data");
return new DynamicDictionary(
data.GetType().GetProperties()
.Where(p => p. && p.CanRead)
.Select(p => new {Name: p.Name, Value: p.GetValue(data, null)})
.ToDictionary(p => p.Name, p => p.Value)
);
}
}
你必须在DynamicDictionary
中实现一个构造函数来接收IDictionary<string, object>
,但这是件小事。