简体   繁体   English

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

[英]Why can't I do this: dynamic x = new ExpandoObject { Foo = 12, Bar = "twelve" }

Am I doing something wrong, or is the following code really not possible?我做错了什么,还是下面的代码真的不可能?

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

If this really isn't possible, is there another one-line way to instantiate an ExpandoObject with two properties?如果这真的不可能,是否有另一种单行方法来实例化具有两个属性的 ExpandoObject?

Why would the C# team opt to disallow the same initialization syntax as for regular objects, anonymous objects, and enumerables/lists?为什么 C# 团队会选择禁止与常规对象、匿名对象和可枚举/列表相同的初始化语法?

Update更新

I asked this question because I was trying show a Pearl enthusiast the cool new dynamic features of C#, but then I was stalled by not being able to do what I thought was a logical instantiation of an ExpandoObject .我问这个问题是因为我试图向 Pearl 爱好者展示 C# 很酷的新动态特性,但后来我因无法执行我认为是ExpandoObject的逻辑实例化而停滞不前。 Thanks to Hans Passant's answer, I realize that ExpandoObject was the wrong tool for the job.感谢 Hans Passant 的回答,我意识到ExpandoObject是不适合这项工作的工具。 My real goal was to use the dynamic features of C# to return two named values from a method.我的真正目标是使用 C# 的动态特性从一个方法返回两个命名值。 As Hans points out, the dynamic keyword is perfect for this.正如汉斯指出的那样, dynamic关键字非常适合这一点。 I didn't need an ExpandoObject , with all its overhead, to do this.我不需要ExpandoObject及其所有开销来执行此操作。

So, if you want to return a pair of named values from a method, and you are not concerned about type safety, Intellisense, refactoring, or performance, this works quite nicely:所以,如果你想从一个方法返回一对命名值,并且你不关心类型安全、智能感知、重构或性能,那么这个工作非常好:

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

Usage:用法:

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

Am I doing something wrong, or is the following code really not possible?我做错了什么,还是下面的代码真的不可能?

It's really not possible.这真的不可能。 The thing on the left of the assignment operator has to be a property or field known at compile time, and obviously that is not the case for expando objects.赋值运算符左侧的内容必须是编译时已知的属性或字段,显然 expando 对象不是这种情况。

Why would the C# team opt to disallow the same initialization syntax as for regular objects, anonymous objects, and enumerables/lists?为什么 C# 团队会选择禁止使用与常规对象、匿名对象和可枚举/列表相同的初始化语法?

The way you phrase the question indicates the logical error.你表述问题的方式表明了逻辑错误。 Features are not implemented by default and then we run around disallowing almost all of them because we think they're a bad idea!默认情况下不会实现功能,然后我们到处禁止几乎所有功能,因为我们认为它们是一个坏主意! Features are unimplemented by default, and have to be implemented in order to work.默认情况下未实现功能,必须实现才能工作。

The first step in implementing any feature is that someone has to think of it in the first place.实现任何功能的第一步是有人必须首先考虑它。 To my knowledge, we never did.据我所知,我们从未这样做过。 In particular, it would have been quite difficult for the person designing object initializers in 2006 to know that in 2010 we were going to add "dynamic" to the language, and design the feature accordingly.特别是,2006 年设计对象初始值设定项的人很难知道 2010 年我们将在语言中添加“动态”并相应地设计功能。 Features are always designed by designers who move forwards in time, not backwards in time.功能总是由在时间上前进而不是在时间上倒退的设计师设计。 We only remember the past, not the future.我们只记得过去,不记得未来。

Anyway, it's a nice idea so thanks for sharing it.无论如何,这是一个好主意,所以感谢分享。 Now that someone has thought of it, we can then work on the next steps, like deciding if it is the best idea upon which we can spend our limited budget, designing it, writing the specification, implementing it, testing it, documenting it and shipping it to customers.既然有人已经想到了,我们就可以进行下一步工作,例如决定它是否是我们可以花费有限预算的最佳想法,设计它,编写规范,实施它,测试它,记录它以及运送给客户。

I wouldn't expect any of that to happen any time soon;我不希望这些事情很快发生。 we're a bit busy with this whole async-and-WinRT business that we announced at Build last week.我们对上周在 Build 上宣布的整个 async-and-WinRT 业务有点忙。

There's a better mouse trap than ExpandoObject.有比 ExpandoObject 更好的捕鼠器。 The dynamic keyword handles anonymous types with aplomb: dynamic关键字沉着地处理匿名类型:

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

One unfortunate problem is that the C# compiler generates the anonymous type giving the members only internal accessibility.一个不幸的问题是 C# 编译器生成匿名类型,只为成员提供内部可访问性。 Which means that you'll get a runtime error when you try to access the members in another assembly.这意味着当您尝试访问另一个程序集中的成员时,您将收到运行时错误。 Bummer.无赖。

Consider a tuple , much improved in C# v7.考虑一个元组,在 C# v7 中有很大改进。

Dynamitey (open source PCL and found in nuget) has a syntax for initializing expandos that can be inline. Dynamitey(开源 PCL,可在 nuget 中找到)具有用于初始化可以内联的 expandos 的语法。

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

One workaround that worked for me is this ToExpando() extension method by Yan Cui ( source ):对我ToExpando()一种解决方法是 Yan Cui( 来源)的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;
    }
}

Example usage:用法示例:

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();

Then can use properties like XEntryItems.Name .然后可以使用XEntryItems.Name类的XEntryItems.Name

PS: Please vote here to support object initializers on ExpandoObjects. PS:请在这里投票以支持 ExpandoObjects 上的对象初始值设定项。

of course you can!!!当然可以!!! with the extended method below you can make something like this:使用下面的扩展方法,你可以做这样的事情:

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

here goes the code这是代码

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

the Set method is intended for adding more properties (for scenarios where you don't know the property name at compile time) Set 方法用于添加更多属性(适用于您在编译时不知道属性名称的情况)

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

and since it's dynamic could just make并且因为它是动态的

x.LastName = "Gates";

That kind of initializer syntax is possible because there are already property with a get and setter.这种初始化语法是可能的,因为已经有带有 get 和 setter 的属性。 With the expando object there aren't those properties yet from what I can tell.对于 expando 对象,据我所知还没有这些属性。

public static class ExpandoObjectExtentions
{
    public static void Add(this ExpandoObject obj, string key, object val)
    {
        ((IDictionary<string, object>)obj).Add(key, val);
    }
}

Much simpler way to do this:更简单的方法来做到这一点:

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

Then just call the parse function and pass in a dictionary as a parameter.然后只需调用 parse 函数并传入字典作为参数。 This of course can be implemented into a method instead of a function.这当然可以实现为方法而不是函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么我不能索引到 ExpandoObject? - Why can't I index into an ExpandoObject? 为什么我不能在隐式转换中返回接口,但ExpandoObject可以吗? - Why can't I return an Interface on implicit casting, but ExpandoObject can? 为什么我不能转换 Foo<t?> 给富<t></t></t?> - Why can I not convert Foo<T?> to Foo<T> 为什么必须手动创建ExpandoObject才能正确使用dynamic关键字? - Why do I have to manually create ExpandoObject to properly use the dynamic keyword? 为什么我不能转换Foo <Bar> 到IFoo <IBar> - Why can I not convert a Foo<Bar> to IFoo<IBar> 如何检测ExpandoObject与动态对象? - How do I detect an ExpandoObject vs a Dynamic Object? C#List <Interface>:为什么你不能做`List <IFoo> foo = new List <Bar>();` - C# List<Interface>: why you cannot do `List<IFoo> foo = new List<Bar>();` 为什么我不能将List <List <Foo >>传递给IEnumerable <IEnumerable <Foo >> - Why can't I pass a List<List<Foo>> to an IEnumerable<IEnumerable<Foo>> 为什么“ foo = new double [int x,int y]”是合法的,而“ foo = new double [int x] [int y]”却不合法? - Why “foo = new double[int x, int y]” is legal but not “foo = new double[int x][int y]”? 为什么 `foo is not { } bar` 在语义上不等同于 `?(foo is { } bar)`? - Why is `foo is not { } bar` not semantically equivalent to `!(foo is { } bar)`?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM