60

我今天遇到了以下问题,我想知道是否有解决我的问题的方法。

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

到目前为止效果很好。

我遇到的问题是从 BindingSource 的“当前”属性中取出 Id,因为我无法将其转换回匿名类型:

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

我想没有办法找出“Current”的类型并访问“Id”属性吗?也许有人有一个很好的解决方案......

我知道还有其他(也是更好的)方法来获取 Id(反射,从 ComboBox 读取值,不使用匿名 tpyes,...)我只是好奇是否可以从 bsOptions 中获取类型。当前以优雅的方式。

4

7 回答 7

96

请注意,根据评论,我只想指出,当您需要像这样在程序中传递它时,我也建议使用真实类型。匿名类型应该一次只在本地使用一种方法(在我看来),但无论如何,这是我的其余答案。


您可以通过欺骗编译器为您推断正确的类型来使用技巧来做到这一点:

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

诀窍是在程序集中,相同的匿名类型(相同的属性,相同的顺序)解析为相同的类型,这使得上述技巧有效。

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

用法:

var value = x.CastTo(a);

但我们真的在这里挑战极限。使用真正的类型,它的外观和感觉也会更干净。

于 2009-09-11T08:49:19.773 回答
19

尝试使用动态类型,而不是转换为您的自定义类型。

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

private void cmdOK_Click(object sender, EventArgs e)
{
    dynamic option = bsOptions.Current;
    if (option.Id == 1) { doSomething(); }
      else { doSomethingElse(); }
}
于 2012-05-20T09:35:40.900 回答
8

引用MSDN

匿名类型不能转换为除对象之外的任何接口或类型。

于 2009-09-11T08:41:35.000 回答
6

在 C# 3.0 中,这是不可能的。您必须等待 C# 4.0,它允许在运行时使用“动态”变量访问属性。

于 2009-09-11T08:42:52.273 回答
3
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);
于 2012-04-03T17:20:45.230 回答
1

你可以试试这个:

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

请参阅:不能从方法返回匿名类型?真的吗?

于 2009-09-11T08:55:23.067 回答
1

您还可以使用该语法直接声明一组匿名类型:

var data = new [] {
  new {Id = 0, Name = "Foo"},
  new {Id = 42, Name = "Bar"},
};
于 2011-02-04T16:23:58.427 回答