Cast to Anonymous Type
今天我遇到了以下问题,我想知道我的问题是否有解决办法。
我的想法是构建匿名类,并将其用作WinForm绑定源的数据源:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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"); } |
到目前为止还可以。
我遇到的问题是从bindingSource的"current"属性中获取ID,因为我无法将其强制转换回匿名类型:
1 2 3 4 | private void cmdOK_Click(object sender, EventArgs e) { var option = (???)bsOptions.Current; } |
号
我想没有办法找出"current"的类型并访问"id"属性?也许有人有一个很好的解决办法…
我知道还有其他(也是更好的)方法来获取ID(反射,从组合框中读取值,而不是使用匿名tpyes,…)如果可以从bsoptions中获取类型,我会很勇敢。目前以一种优雅的方式。
注意,根据注释,我想指出的是,当您需要像这样传递给程序时,我也推荐使用真正的类型。匿名类型应该一次只在本地一个方法中使用(在我看来),但无论如何,这里是我的其余答案。
您可以使用一个技巧,通过诱使编译器为您推断正确的类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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; } } } |
诀窍是,在程序集中,相同的匿名类型(相同的属性,相同的顺序)解析为相同的类型,这使得上述诀窍起作用。
1 2 3 4 5 6 | 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; } |
号
用途:
1 | var value = x.CastTo(a); |
但我们确实在挑战极限。使用真正的类型,它会看起来和感觉更清洁。
不要强制转换为自定义类型,请尝试使用动态类型。
事件处理程序如下所示:
1 2 3 4 5 6 | private void cmdOK_Click(object sender, EventArgs e) { dynamic option = bsOptions.Current; if (option.Id == 1) { doSomething(); } else { doSomethingElse(); } } |
。
引用msdn:
An anonymous type cannot be cast to any interface or type except for object.
号
在C 3.0中,这是不可能的。您必须等待C 4.0,它允许在运行时使用"动态"变量访问属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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") }; } |
…那么你要做的就是:
1 2 |
。
您还可以使用以下语法直接声明匿名类型数组:
1 2 3 4 5 6 |
。
请参见:无法从方法返回匿名类型?真的?