Convertido para tipo anônimo
-
05-07-2019 - |
Pergunta
Eu tive o seguinte problema hoje, e eu queria saber se existe uma solução para o meu problema.
A minha ideia era construir classes anônimas e usá-lo como uma fonte de dados para um 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");
}
Isso funciona muito bem até agora.
O problema que tive é obter Id fora da propriedade "Current" da BindingSource, porque eu não posso lançá-lo de volta para o tipo anônimo:
private void cmdOK_Click(object sender, EventArgs e)
{
var option = (???)bsOptions.Current;
}
Eu acho que não há nenhuma maneira de descobrir o tipo de "atual" e acesso a "Id" Propriedade? Talvez alguém tenha uma boa solução ...
Eu sei que há outros (e também melhores) maneiras de obter o Id (reflexão, a leitura do valor da caixa de combinação, não usando tpyes anônimos, ...) Eu sou apenas courious se é possível obter a fora Tipo de bsOptions.Current de uma forma elegante.
Solução
Nota ??em> , de acordo com o comentário, eu gostaria apenas de salientar que eu também recomendo o uso de um tipo real quando você precisa passá-lo ao redor do programa como isto. Tipos anônimos só deve realmente ser usado localmente em um único método de cada vez (na minha opinião), mas de qualquer maneira, aqui está o resto da minha resposta.
Você pode fazer isso usando um truque, enganando o compilador para inferir o tipo certo para você:
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;
}
}
}
O truque é que no interior do conjunto, o mesmo tipo anónimo (mesmas propriedades, mesma ordem) é resolvido para o mesmo tipo, que faz com que o truque acima trabalho.
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;
}
uso:
var value = x.CastTo(a);
Mas nós realmente estamos empurrando os limites aqui. Utilize um tipo real, ele vai olhar e sentir mais limpo também.
Outras dicas
Em vez de moldar a seu tipo personalizado tentativa usando o tipo de dinâmica.
O seu manipulador de eventos seria algo parecido com isto:
private void cmdOK_Click(object sender, EventArgs e)
{
dynamic option = bsOptions.Current;
if (option.Id == 1) { doSomething(); }
else { doSomethingElse(); }
}
Para citar MSDN :
Tipo Um anônimo não pode ser convertido para qualquer interface ou tipo de exceção de objeto.
Em C # 3.0, isso não é possível. Você vai ter que esperar para C # 4.0, que permite aceder às propriedades em tempo de execução usando variáveis ??"dinâmicos".
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")
};
}
.... então para lançar você vai fazer:
var a = new { Id = 1, FirstName = "Bob", LastName="Nam" };
SomeClass myNewVar = CastToSomeClass(a);
Você pode tentar o seguinte:
private void cmdOK_Click(object sender, EventArgs e)
{
var option = Cast(bsOptions.Current, new { Id = 0, Option = "", Description = "" });
}
Você também pode declarar uma matriz de tipos anônimos diretamente com essa sintaxe:
var data = new [] {
new {Id = 0, Name = "Foo"},
new {Id = 42, Name = "Bar"},
};