为什么我不能这样做: 动态 x = 新的扩展对象{ Foo = 12,Bar = “12”}

是我做错了什么,还是下面的代码真的不可能?

dynamic x = new ExpandoObject { Foo = 12, Bar = "twelve" };

如果这真的是不可能的,是否有另一种一行的方法来实例化一个具有两个属性的 expdoObject?

为什么 C # 团队选择不允许使用与常规对象、匿名对象和可枚举数据/列表相同的初始化语法?

更新

我问这个问题是因为我想向一个 Pearl 爱好者展示 C # 很酷的新动态特性,但是后来我因为不能做我认为是 ExpandoObject的逻辑实例化而停滞不前。多亏了汉斯 · 帕桑特的回答,我才意识到 ExpandoObject并不适合这项工作。我真正的目标是使用 C # 的动态特性从一个方法返回两个命名值。正如汉斯所指出的,dynamic关键字非常适合这种情况。我不需要 ExpandoObject和它的所有开销来做这个。

因此,如果您想从一个方法返回一对命名值,并且您不关心类型安全、智能感知、重构或性能,那么这种方法工作得很好:

public dynamic CreateFooBar()
{
return new { Foo = 42, Bar = "Hello" };
}

用法:

dynamic fooBar = CreateFooBar();
var foo = fooBar.Foo;
var bar = fooBar.Bar;
22658 次浏览

是我做错了什么,还是下面的代码真的不可能?

这真的不可能。赋值操作符左边的内容必须是在编译时已知的属性或字段,而对于扩展对象显然不是这种情况。

为什么 C # 团队选择不允许使用与常规对象、匿名对象和可枚举数据/列表相同的初始化语法?

你提问的方式表明了逻辑错误。特性在默认情况下并没有被实现,然后我们就不允许几乎所有的特性,因为我们认为它们是一个坏主意!特性默认是 未实施,必须是 实施才能工作。

实现任何特性的第一步都是必须有人首先考虑它。据我所知,我们从来没有。特别是,对于在2006年设计对象初始化器的人来说,要知道在2010年我们要向语言中添加“动态”,并相应地设计特性是相当困难的。功能总是由设计师设计谁移动 前进的时间,而不是 倒过来的时间。我们只记得过去,不记得未来。

不管怎样,这是个好主意,谢谢分享。既然有人已经想到了它,那么我们就可以开始下一步的工作,比如决定它是否是我们有限的预算中可以花费的最好的想法,设计它,编写规范,实现它,测试它,记录它,并将它发送给客户。

我不指望这些会很快发生; 我们有点忙于上周在 Build 中宣布的整个异步和 WinRT 业务。

这种初始化器语法是可能的,因为已经有带 get 和 setter 的属性。对于 expdo 对象,目前还没有这些属性。

Dynamitey (开放源码 PCL,可以在 nuget 中找到)有一个可以内联的 正在初始化扩展语法。

 //using Dynamitey.DynamicObjects
var x = Build<ExpandoObject>.NewObject(Foo:12, Bar:"twelve");

还有一个比 ExpendoObject 更好的捕鼠器。 充满活力关键字可以泰然处理匿名类型:

class Program {
static void Main(string[] args) {
dynamic x = new { Foo = 12, Bar = "twelve" };
Display(x);
}
static void Display(dynamic x) {
Console.WriteLine(x.Foo);
Console.WriteLine(x.Bar);
}
}

一个不幸的问题是,C # 编译器生成的匿名类型只赋予成员 内部可访问性。这意味着当您尝试访问另一个程序集中的成员时,将得到一个运行时错误。真扫兴。

考虑一下 一对,它在 C # v7中得到了很大的改进。

对我有效的一个变通方法是闫翠的 ToExpando()扩展方法(来源) :

public static class DictionaryExtensionMethods
{
/// <summary>
/// Extension method that turns a dictionary of string and object to an ExpandoObject
/// </summary>
public static ExpandoObject ToExpando(this IDictionary<string, object> dictionary)
{
var expando = new ExpandoObject();
var expandoDic = (IDictionary<string, object>) expando;


// go through the items in the dictionary and copy over the key value pairs)
foreach (var kvp in dictionary)
{
// if the value can also be turned into an ExpandoObject, then do it!
if (kvp.Value is IDictionary<string, object>)
{
var expandoValue = ((IDictionary<string, object>) kvp.Value).ToExpando();
expandoDic.Add(kvp.Key, expandoValue);
}
else if (kvp.Value is ICollection)
{
// iterate through the collection and convert any strin-object dictionaries
// along the way into expando objects
var itemList = new List<object>();
foreach (var item in (ICollection) kvp.Value)
{
if (item is IDictionary<string, object>)
{
var expandoItem = ((IDictionary<string, object>) item).ToExpando();
itemList.Add(expandoItem);
}
else
{
itemList.Add(item);
}
}


expandoDic.Add(kvp.Key, itemList);
}
else
{
expandoDic.Add(kvp);
}
}


return expando;
}
}

示例用法:

public const string XEntry = "ifXEntry";
public static readonly dynamic XEntryItems = new Dictionary<string, object>
{
{ "Name",                     XEntry + ".1" },
{ "InMulticastPkts",          XEntry + ".2" },
{ "InBroadcastPkts",          XEntry + ".3" },
{ "OutMulticastPkts",         XEntry + ".4" },
{ "OutBroadcastPkts",         XEntry + ".5" },
{ "HCInOctets",               XEntry + ".6" },
{ "HCInUcastPkts",            XEntry + ".7" },
{ "HCInMulticastPkts",        XEntry + ".8" },
{ "HCInBroadcastPkts",        XEntry + ".9" },
{ "HCOutOctets",              XEntry + ".10" },
{ "HCOutUcastPkts",           XEntry + ".11" },
{ "HCOutMulticastPkts",       XEntry + ".12" },
{ "HCOutBroadcastPkts",       XEntry + ".13" },
{ "LinkUpDownTrapEnable",     XEntry + ".14" },
{ "HighSpeed",                XEntry + ".15" },
{ "PromiscuousMode",          XEntry + ".16" },
{ "ConnectorPresent",         XEntry + ".17" },
{ "Alias",                    XEntry + ".18" },
{ "CounterDiscontinuityTime", XEntry + ".19" },
}.ToExpando();

然后可以使用像 XEntryItems.Name这样的属性。

PS: 请投票 给你以支持 ExpendoObjects 上的对象初始化器。

做到这一点的方法要简单得多:

Func<Dictionary<string, object>, ExpandoObject> parse = dict =>
{
var expando = new ExpandoObject();
foreach (KeyValuePair<string, object> entry in dict)
{
expando.Add(entry.Key, entry.Value);
}
return expando;
};

然后调用解析函数并将 dictionary 作为参数传入。 这当然可以实现成一个方法而不是一个函数。

你当然可以! ! ! 使用下面的扩展方法,您可以创建如下内容:

dynamic x = (new { Foo = 12, Bar = "twelve" }).ToExpando();

密码来了

public static class MyExpando
{


public static void Set(this ExpandoObject obj, string propertyName, object value)
{
IDictionary<string, object> dic = obj;
dic[propertyName] = value;
}


public static ExpandoObject ToExpando(this object initialObj)
{
ExpandoObject obj = new ExpandoObject();
IDictionary<string, object> dic = obj;
Type tipo = initialObj.GetType();
foreach(var prop in tipo.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
dic.Add(prop.Name, prop.GetValue(initialObj));
}
return obj;
}
}

Set 方法用于添加更多属性(用于在编译时不知道属性名的情况)

x.Set("Name", "Bill");

因为它是动态的

x.LastName = "Gates";