关于c#:转换为匿名类型

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
var a = new { Id = 1, FirstName ="Bob", LastName="Nam" };
SomeClass myNewVar = CastToSomeClass(a);


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

1
2
3
4
5
6
var data = new [] {
  new {Id = 0, Name ="Foo
<p><center>[wp_ad_camp_2]</center></p><hr><P>您可以尝试以下操作:</P>[cc lang="
csharp"]private void cmdOK_Click(object sender, EventArgs e)
{
    var option = Cast(bsOptions.Current, new { Id = 0, Option ="
", Description ="" });
}

请参见:无法从方法返回匿名类型?真的?