投射到匿名types

我今天遇到了以下问题,而且我想知道是否有针对我的问题的解决scheme。

我的想法是build立匿名类,并将其用作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"); } 

迄今为止工作正常。

我遇到的问题是将Id从BindingSource的“Current”属性中取出,因为我无法将其转换回Anonymous Type:

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

我想没有办法找出“当前”的types,并访问“Id”属性? 也许有人有一个好的解决scheme…

我知道有其他(也有更好的)方法来获得Id(reflection,从ComboBox中读取值,而不是使用匿名tpyes,…)。如果可以从bsOptions中获取Type,我只是非常棒。目前在一个优雅的方式。

请注意 ,根据评论,我只想指出,我也推荐使用一个真正的types,当你需要像这样传递给程序。 匿名types应该只能用一种方法在本地使用(在我看来),但无论如何,这里是我的答案的其余部分。


你可以通过欺骗编译器来为你推断正确的types:

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

诀窍是在程序集内,相同的匿名types(相同的属性,相同的顺序)parsing为相同的types,这使得上面的技巧工作。

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

用法:

 var value = x.CastTo(a); 

但是我们真的在这里极限 使用一个真正的types,它会看起来更干净。

而不是铸造到您的自定义types尝试使用dynamictypes。

你的事件处理程序看起来像这样:

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

引用MSDN :

除了对象之外,匿名types不能转换为任何接口或types。

在C#3.0中,这是不可能的。 您将不得不等待C#4.0,它允许在运行时使用“dynamic”variables访问属性。

你可以试试这个:

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

请参阅: 不能从方法返回匿名types? 真?

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

….然后投你会做:

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

你也可以用这个语法直接声明一个匿名types的数组:

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