web-dev-qa-db-fra.com

Pourquoi ne puis-je pas faire ceci: x dynamique = nouveau ExpandoObject {Foo = 12, Bar = "douze"}

Est-ce que je fais quelque chose de mal ou le code suivant n'est-il vraiment pas possible?

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

Si ce n'est vraiment pas possible, existe-t-il un autre moyen sur une ligne pour instancier un ExpandoObject avec deux propriétés?

Pourquoi l'équipe C # aurait-elle choisi d'interdire la même syntaxe d'initialisation que pour les objets ordinaires, les objets anonymes et les énumérables/listes?

Mettre à jour

J'ai posé cette question parce que j'essayais de montrer à un passionné de Pearl les nouvelles fonctionnalités dynamiques de C #, mais j'ai été bloqué par l'impossibilité de faire ce que je pensais être une instanciation logique d'une ExpandoObject. Grâce à la réponse de Hans Passant, je me rends compte que ExpandoObject était le mauvais outil pour le travail. Mon véritable objectif était d'utiliser les fonctionnalités dynamiques de C # pour renvoyer deux valeurs nommées d'une méthode. Comme Hans le fait remarquer, le mot clé dynamic est parfait pour cela. Je n'avais pas besoin d'une ExpandoObject, avec tous ses frais généraux, pour faire cela.

Ainsi, si vous souhaitez renvoyer une paire de valeurs nommées d'une méthode et que vous ne vous inquiétez pas du type sécurité, Intellisense, refactoring ou performance, cela fonctionne plutôt bien:

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

Usage:

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

Est-ce que je fais quelque chose de mal ou le code suivant n'est-il vraiment pas possible?

C'est vraiment pas possible. La chose à gauche de l'opérateur d'affectation doit être une propriété ou un champ connu au moment de la compilation, ce qui n'est évidemment pas le cas pour les objets expando.

Pourquoi l'équipe C # aurait-elle choisi d'interdire la même syntaxe d'initialisation que pour les objets ordinaires, les objets anonymes et les énumérables/listes?

La façon dont vous formulez la question indique l'erreur logique. Les fonctionnalités ne sont pas implémentées par défaut, puis nous les refusons presque toutes car nous pensons qu'elles sont une mauvaise idée! Les fonctionnalités sont non implémentées par défaut, et doivent être implémentées pour fonctionner. 

La première étape dans la mise en œuvre de toute fonctionnalité est que quelqu'un doit y penser en premier lieu. À ma connaissance, nous ne l'avons jamais fait. En particulier, il aurait été assez difficile pour le concepteur d’initialiseurs d’objets en 2006 de savoir qu’en 2010, nous allions ajouter de la dynamique au langage et concevoir l’option en conséquence. Les fonctionnalités sont toujours conçues par des concepteurs qui avancent en avant dans le temps, pas en arrière dans le temps. Nous ne nous souvenons que du passé, pas de l'avenir.

En tout cas, c'est une bonne idée, alors merci de la partager. Maintenant que quelqu'un y a pensé, nous pouvons alors travailler sur les prochaines étapes, comme décider si c'est la meilleure idée sur laquelle nous pouvons utiliser notre budget limité, le concevoir, rédiger la spécification, la mettre en œuvre, la tester et l'expédier aux clients.

Je ne m'attendrais pas à ce que cela se produise de si tôt; nous sommes un peu occupés par toute cette activité asynchrone et WinRT que nous avons annoncée à Build la semaine dernière.

46
Eric Lippert

Il existe un meilleur piège à la souris que ExpandoObject. Le mot clé dynamic gère les types anonymes avec 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);
    }
}

Un problème regrettable est que le compilateur C # génère le type anonyme ne donnant aux membres que _ l'accessibilité internal. Cela signifie que vous obtiendrez une erreur d'exécution lorsque vous tenterez d'accéder aux membres d'un autre assembly. Bummer.

Considérons un tuple , bien amélioré en C # v7.

37
Hans Passant

Dynamitey (PCL open source et trouvé dans nuget) a une syntaxe pour initialiser expandos qui peut être en ligne.

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

Une solution de contournement qui a fonctionné pour moi est cette méthode d'extension ToExpando() par Yan Cui ( 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;
    }
}

Exemple d'utilisation:

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

Ensuite, vous pouvez utiliser des propriétés comme XEntryItems.Name.

PS: Veuillez voter ici pour prendre en charge les initialiseurs d’objet sur ExpandoObjects.

2
orad

Ce type de syntaxe d'initialisation est possible car il existe déjà des propriétés avec get et setter. Avec l'objet expando, il n'y a pas encore ces propriétés de ce que je peux dire.

0
Cubicle.Jockey

Manière beaucoup plus simple de faire ceci:

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

Ensuite, appelez simplement la fonction d'analyse et transmettez un dictionnaire en tant que paramètre . Cela peut bien sûr être implémenté dans une méthode à la place d'une fonction.

0
Adrian Vella