it-swarm.cn

为什么我不能这样做:dynamic x = new ExpandoObject {Foo = 12,Bar =“12”}}

我做错了什么,或者以下代码真的不可能?

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

如果这确实不可能,是否有另一种单行方式来实例化具有两个属性的ExpandoObject?

为什么C#团队会选择禁止使用与常规对象,匿名对象和枚举/列表相同的初始化语法?

更新

我问这个问题是因为我试图向珍珠爱好者展示C#的酷炫新动态特性,但后来由于无法做到我认为是ExpandoObject的逻辑实例化而陷入困境。感谢Hans Passant的回答,我意识到ExpandoObject是错误的工具。我的真正目标是使用C#的动态功能从方法返回两个命名值。正如Hans指出的那样,dynamic关键字非常适用于此。我不需要一个带有所有开销的ExpandoObject来执行此操作。

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

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

用法:

dynamic fooBar = CreateFooBar();
var foo = fooBar.Foo;
var bar = fooBar.Bar;
57
devuxer

我做错了什么,或者以下代码真的不可能?

这真的不可能。赋值运算符左侧的东西必须是编译时已知的属性或字段,显然对于expando对象不是这种情况。

为什么C#团队会选择禁止使用与常规对象,匿名对象和枚举/列表相同的初始化语法?

您表达问题的方式表示逻辑错误。默认情况下没有实现功能,然后我们几乎不允许使用它们,因为我们认为它们是个坏主意!功能是 未实现 默认情况下,必须 实现 才能工作。

实现任何功能的第一步是有人必须首先考虑它。据我所知,我们从未这样做过。特别是,2006年设计对象初始化器的人很难知道在2010年我们将为语言添加“动态”,并相应地设计该功能。功能总是由设计师设计的,这些设计师是移动 向前 及时,而不是 向后 及时。我们只记得过去,而不是未来。

无论如何,这是一个不错的主意,所以感谢分享它。现在有人已经想到了它,我们就可以开始接下来的步骤了,比如决定它是否是最好的想法,我们可以花费有限的预算,设计它,编写规范,实现它,测试它,记录它和将其运送给客户。

我不希望任何这种情况很快发生;我们有点忙于上周在Build上宣布的整个异步和WinRT业务。

47
Eric Lippert

有一个比ExpandoObject更好的鼠标陷阱。 dynamic keyword使用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#编译器生成匿名类型,只给成员 internal accessibility。这意味着当您尝试访问另一个程序集中的成员时,您将收到运行时错误。游民。

考虑 一个元组 ,在C#v7中有很大改进。

38
Hans Passant

Dynamitey(开源PCL,在nuget中找到)具有 初始化expandos的语法 可以是内联的。

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

一个对我有用的解决方法是Yan Cui的这个ToExpando()扩展方法( source ):

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:请投票 这里 支持ExpandoObjects上的对象初始值设定项。

2
orad

这种初始化器语法是可能的,因为已经存在具有get和setter的属性。使用expando对象,我所知道的还没有那些属性。

0
Cubicle.Jockey

更简单的方法:

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;
};

然后只需调用parse函数并将字典作为参数传入。这当然可以实现为方法而不是函数。

0
Adrian Vella