为什么我不能这样做:dynamic x = new ExpandoObject {Foo = 12,Bar =“twelve”}
我做错了什么,或者是下面的代码真的不可能?
dynamic x = new ExpandoObject { Foo = 12, Bar = "twelve" };
如果这是不可能的,是否有另一种单行的方式来实例化具有两个属性的ExpandoObject?
为什么C#团队会select禁用与常规对象,匿名对象和枚举/列表相同的初始化语法?
更新
我问这个问题是因为我试图向Pearl发烧友展示C#的新dynamic特性,但后来因为无法做到我认为是ExpandoObject
的逻辑实例而停滞不前。 感谢Hans Passant的回答,我意识到ExpandoObject
是这个工作的错误工具。 我真正的目标是使用C#的dynamic特性从方法返回两个命名值。 正如汉斯所指出的那样, dynamic
关键字是完美的。 我不需要一个具有所有开销的ExpandoObject
来执行此操作。
所以,如果你想从一个方法中返回一对命名值,并且你不关心types安全,Intellisense,重构或者性能,这个工作方式非常好:
public dynamic CreateFooBar() { return new { Foo = 42, Bar = "Hello" }; }
用法:
dynamic fooBar = CreateFooBar(); var foo = fooBar.Foo; var bar = fooBar.Bar;
我做错了什么,或者是下面的代码真的不可能?
这是不可能的。 赋值运算符左边的东西必须是编译时已知的属性或字段,显然expando对象不是这种情况。
为什么C#团队会select禁用与常规对象,匿名对象和枚举/列表相同的初始化语法?
你问题的方式表示逻辑错误。 function没有默认实现,然后我们绕过几乎所有的人,因为我们认为他们是一个坏主意! function默认情况下未实现 ,必须执行才能工作。
实现任何function的第一步是有人必须首先想到它。 据我所知,我们从来没有。 尤其是,2006年devise对象初始化器的人很难知道,2010年我们要为语言添加“dynamic”,并相应地devise这个特性。 function总是由devise师devise的,他们及时向前 ,而不是及时向后 。 我们只记得过去,而不是未来。
无论如何,这是一个很好的主意,所以感谢分享它。 现在有人想到了,接下来我们就可以进行下一步的工作,比如决定是否可以花费我们有限的预算,devise,编写规范,实施,testing,logging,运送给客户。
我不希望这种情况很快发生, 我们在上周在Build上发布的这整个asynchronous和WinRT业务有点忙。
有一个比ExpandoObject更好的鼠标陷阱。 dynamic关键字处理匿名types与aplomb:
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#编译器生成的匿名types只给予成员内部的可访问性。 这意味着当您尝试访问另一个程序集中的成员时,会出现运行时错误。 游民。
考虑一个元组 ,在C#v7中有了很大的改进。
Dynamitey(开源PCL,在nuget中find)有一个初始化可以内联的expandos的语法。
//using Dynamitey.DynamicObjects var x = Build<ExpandoObject>.NewObject(Foo:12, Bar:"twelve");
一个解决方法是我的工作是这个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
这样的XEntryItems.Name
。
PS:请在这里投票支持ExpandoObjects上的对象初始值设定项。
这种初始化语法是可能的,因为已经有一个get和setter的属性。 有了expando对象,就没有那些属性了。