Domanda

Oggi ho avuto il seguente problema e mi chiedevo se esiste una soluzione per il mio problema.

La mia idea era quella di creare classi anonime e usarlo come origine dati per una fonte vincolante WinForm:

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

Finora funziona bene.

Il problema che ho avuto è stato quello di estrarre l'ID da " Current " proprietà di BindingSource, perché non riesco a restituirlo al Tipo anonimo:

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

Suppongo non ci sia modo di scoprire il tipo di " Current " e accedi a " Id " Proprietà? Forse qualcuno ha una buona soluzione ...

So che ci sono altri (e anche migliori) modi per ottenere l'ID (Reflection, leggere il valore da ComboBox, non usare tpyes anonimi, ...) Sono solo coraggioso se è possibile ottenere il Tipo di bsOptions.Corrente in modo elegante.

È stato utile?

Soluzione

Nota , come per il commento, vorrei solo sottolineare che anche io consiglio di usare un tipo reale quando è necessario passarlo intorno al programma come Questo. I tipi anonimi dovrebbero davvero essere usati localmente in un solo metodo alla volta (secondo me), ma comunque, ecco il resto della mia risposta.


Puoi farlo usando un trucco, inducendo il compilatore a dedurre il tipo giusto per te:

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

Il trucco è che all'interno dell'assembly, lo stesso tipo anonimo (stesse proprietà, stesso ordine) si risolve nello stesso tipo, il che fa funzionare il trucco sopra.

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

utilizzo:

var value = x.CastTo(a);

Ma stiamo davvero spingendo i limiti qui. Usa un tipo reale, sembrerà e anche più pulito.

Altri suggerimenti

Invece di trasmettere al tuo tipo personalizzato prova a utilizzare il tipo dinamico.

Il gestore dell'evento sarebbe simile al seguente:

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

Per citare MSDN :

  

Un tipo anonimo non può essere trasmesso a nessuna interfaccia o tipo tranne l'oggetto.

In C # 3.0, questo non è possibile. Dovrai attendere C # 4.0, che consente di accedere alle proprietà in fase di esecuzione utilizzando "dinamico" variabili.

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

.... poi per fare il cast farai:

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

puoi provare questo:

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

vedi: Non riesci a restituire un tipo anonimo dal metodo? Davvero?

Puoi anche dichiarare un array di tipi anonimi direttamente con quella sintassi:

var data = new [] {
  new {Id = 0, Name = "Foo"},
  new {Id = 42, Name = "Bar"},
};
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top