web-dev-qa-db-fra.com

Cast au type anonyme

J'ai eu le problème suivant aujourd'hui, et je me demandais s'il existe une solution à mon problème.

Mon idée était de construire des classes anonymes et de les utiliser comme source de données pour un WinForm BindingSource:

public void Init()
{
    var option1 = new
                  {
                      Id = TemplateAction.Update,
                      Option = "Update the Templates",
                      Description = "Bla bla 1."
                  };

    var option2 = new
                  {
                      Id = TemplateAction.Download,
                      Option = "Download the Templates",
                      Description = "Bla bla 2."
                  };

    var list = new[] {option1, option2}.ToList();

    bsOptions.DataSource = list; // my BindingSource

    // cboTemplates is a ComboBox
    cboTemplates.DataSource = bsOptions; 
    cboTemplates.ValueMember = "Id";
    cboTemplates.DisplayMember = "Option";

    lblInfoTemplates.DataBindings.Add("Text", bsOptions, "Description");
}

Cela fonctionne bien jusqu'à présent.

Le problème que j'ai eu est d'obtenir l'ID de la propriété "Current" de BindingSource, car je ne peux pas le redonner au type anonyme:

private void cmdOK_Click(object sender, EventArgs e)
{
    var option = (???)bsOptions.Current;
}

Je suppose qu’il n’ya aucun moyen de connaître le type de «courant» et d’accéder à la propriété «Id»? Peut-être que quelqu'un a une bonne solution ...

Je sais qu'il existe d'autres moyens (et aussi meilleurs) d'obtenir l'ID (réflexion, lecture de la valeur dans la ComboBox, utilisation de mots anonymes, ...). Je suis simplement curieux de savoir s'il est possible d'obtenir le Type avec bsOptions. Courant d'une manière élégante.

46
gsharp

Note, comme dans le commentaire, je voudrais simplement souligner que je recommande également d'utiliser un type réel lorsque vous devez le faire circuler dans le programme de cette manière. Les types anonymes ne devraient vraiment être utilisés localement que dans une seule méthode à la fois (à mon avis), mais voici le reste de ma réponse.


Vous pouvez le faire en utilisant une astuce, en incitant le compilateur à inférer le bon type pour vous:

using System;

namespace ConsoleApplication4
{
    class Program
    {
        static void Main(string[] args)
        {
            var a = new { Id = 1, Name = "Bob" };
            TestMethod(a);

            Console.Out.WriteLine("Press enter to exit...");
            Console.In.ReadLine();
        }

        private static void TestMethod(Object x)
        {
            // This is a dummy value, just to get 'a' to be of the right type
            var a = new { Id = 0, Name = "" };
            a = Cast(a, x);
            Console.Out.WriteLine(a.Id + ": " + a.Name);
        }

        private static T Cast<T>(T typeHolder, Object x)
        {
            // typeHolder above is just for compiler magic
            // to infer the type to cast x to
            return (T)x;
        }
    }
}

Le truc est qu’à l’intérieur de l’Assemblée, le même type anonyme (mêmes propriétés, même ordre) se résout en un même type, ce qui rend l’astuce ci-dessus plus efficace.

private static T CastTo<T>(this Object value, T targetType)
{
    // targetType above is just for compiler magic
    // to infer the type to cast value to
    return (T)value;
}

usage:

var value = x.CastTo(a);

Mais nous repoussons vraiment les limites ici. Utilisez un type réel, il aura l’air plus propre.

82

Au lieu d'utiliser votre type personnalisé, essayez d'utiliser un type dynamique.

Votre gestionnaire d'événement ressemblerait à quelque chose comme ceci:

private void cmdOK_Click(object sender, EventArgs e)
{
    dynamic option = bsOptions.Current;
    if (option.Id == 1) { doSomething(); }
      else { doSomethingElse(); }
}
18
Marko Juvančič

Pour citer _ MSDN :

Un type anonyme ne peut pas être transtypé vers une interface ou un type, à l'exception d'un objet.

8
Vilx-

En C # 3.0, ce n'est pas possible. Vous devrez attendre C 4.0 qui permet d’accéder aux propriétés à l’exécution à l’aide de variables "dynamiques".

6
Philippe Leybaert

vous pouvez essayer ceci:

private void cmdOK_Click(object sender, EventArgs e)
{
    var option = Cast(bsOptions.Current, new { Id = 0, Option = "", Description = "" });
}

voir: Vous ne pouvez pas retourner le type anonyme de la méthode? Vraiment?

1
manji
public class MyExtensMethods{

    public static T GetPropertyValue<T>(this Object obj, string property)
    {
        return (T)obj.GetType().GetProperty(property).GetValue(obj, null);
    }
}

class SomeClass
{
    public int ID{get;set;}
    public int FullName{get;set;}
}


// casts obj to type SomeClass
public SomeClass CastToSomeClass(object obj)
{
     return new SomeClass()
     {
         ID = obj.GetPropertyValue<int>("Id"),
         FullName = obj.GetPropertyValue<string>("LastName") + ", " + obj.GetPropertyValue<string>("FirstName")
     };
}

.... alors pour faire un casting vous ferez:

var a = new { Id = 1, FirstName = "Bob", LastName="Nam" };
SomeClass myNewVar = CastToSomeClass(a);
1
Tono Nam

Vous pouvez également déclarer un tableau de types anonymes directement avec cette syntaxe:

var data = new [] {
  new {Id = 0, Name = "Foo"},
  new {Id = 42, Name = "Bar"},
};
0
Guillaume86