Почему я не могу сделать это: dynamic x = new ExpandoObject {Foo = 12, Bar = "twelve"} - PullRequest
57 голосов
/ 20 сентября 2011

Я что-то не так делаю, или следующий код действительно невозможен?

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

Если это действительно невозможно, есть ли еще один однострочный способ создания ExpandoObject с двумя свойствами?

Почему команда C # предпочитает запретить тот же синтаксис инициализации, что и для обычных объектов, анонимных объектов и перечислимых / списков?

Обновление

Я задал этот вопрос, потому что я пытался показать энтузиасту Pearl новые крутые динамические возможности C #, но потом я был в тупике из-за того, что не смог сделать то, что мне показалось логическим воплощением ExpandoObject.Благодаря ответу Ханса Пассанта я понимаю, что ExpandoObject был неподходящим инструментом для работы.Моя настоящая цель состояла в том, чтобы использовать динамические возможности C # для возврата двух именованных значений из метода.Как указывает Ганс, ключевое слово dynamic идеально подходит для этого.Для этого мне не понадобился ExpandoObject со всеми его издержками.

Итак, если вы хотите вернуть пару именованных значений из метода и вас не беспокоит безопасность типов,Intellisense, рефакторинг или производительность, это прекрасно работает:

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

Использование:

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

Ответы [ 6 ]

47 голосов
/ 20 сентября 2011

Я что-то не так делаю, или следующий код действительно невозможен?

Это действительно невозможно. Объект слева от оператора присваивания должен быть свойством или полем, известным во время компиляции, и, очевидно, это не относится к объектам расширения.

Почему команда C # предпочла бы запретить тот же синтаксис инициализации, что и для обычных объектов, анонимных объектов и перечисляемых / списков?

То, как вы формулируете вопрос, указывает на логическую ошибку. По умолчанию функции не реализованы, и тогда мы убегаем, закрывая почти все из них, потому что считаем их плохой идеей! Функции не реализованы по умолчанию, и должны быть реализованы , чтобы работать.

Первый шаг в реализации любой функции заключается в том, что кто-то должен думать об этом в первую очередь. Насколько мне известно, мы никогда не делали. В частности, человеку, проектирующему инициализаторы объектов в 2006 году, было бы довольно сложно понять, что в 2010 году мы собираемся добавить в язык «динамический» и соответствующим образом спроектировать эту функцию. Функции всегда разрабатываются дизайнерами, которые перемещаются вперед во времени, а не назад во времени. Мы помним только прошлое, а не будущее.

В любом случае, это хорошая идея, так что спасибо, что поделились ею. Теперь, когда кто-то подумал об этом, мы можем приступить к следующим шагам, например, решить, является ли это наилучшей идеей, на которую мы можем потратить наш ограниченный бюджет, разработать его, написать спецификацию, реализовать ее, протестировать, документировать ее и доставка его клиентам.

Я бы не ожидал, что это случится в ближайшее время; мы немного заняты всем этим бизнесом по асинхронизации и WinRT, который мы объявили на Build на прошлой неделе.

38 голосов
/ 20 сентября 2011

Есть лучшая ловушка мыши, чем ExpandoObject.Ключевое слово dynamic обрабатывает анонимные типы с помощью 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 # генерирует анонимный тип, предоставляя только членам внутреннюю доступность.Это означает, что вы получите ошибку времени выполнения при попытке доступа к элементам в другой сборке.Облом.

Рассмотрим кортеж , значительно улучшенный в C # v7.

10 голосов
/ 20 сентября 2011

Dynamitey (PCL с открытым исходным кодом, найденный в nuget) имеет синтаксис для инициализации расширения , которое может быть встроенным.

 //using Dynamitey.DynamicObjects
 var x = Build<ExpandoObject>.NewObject(Foo:12, Bar:"twelve");
2 голосов
/ 03 марта 2017

Один из подходов, который мне помог, - это метод расширения 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.

0 голосов
/ 27 апреля 2018

Намного проще сделать это:

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

Затем просто вызовите функцию анализа и передайте словарь в качестве параметра. Это, конечно, может быть реализовано в методе вместо функции.

0 голосов
/ 20 сентября 2011

Такой синтаксис инициализатора возможен, потому что уже есть свойство с get и setter. С объектом раскрытия пока нет тех свойств из того, что я могу сказать.

...