【问题标题】:Cast to Anonymous Type转换为匿名类型
【发布时间】:2010-11-27 10:34:11
【问题描述】:

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

我的想法是构建匿名类并将其用作 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.Current 的优雅方式。

【问题讨论】:

  • Br...匿名类可能有用(有时),但实际上,那样使用,对我来说这是对 VB 时代的回归:/。
  • 等到动态进入场景,很高兴我们只看到有关传递匿名对象的问题。
  • 好吧,运气好的话,我们将在标签上拥有一个全新的“marquee”属性:D

标签: c# anonymous-types anonymous-class


【解决方案1】:

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


你可以使用一个技巧,通过欺骗编译器为你推断出正确的类型:

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

但我们确实在挑战极限。使用真正的字体,它的外观和感觉也会更干净。

【讨论】:

  • 我不喜欢这样,因为它容易出错,最好只创建一个实际的类来保存值。
  • 根据 Mads Torgersen 的说法,C# 团队将这种技巧称为“以身作则”。见他对这篇文章的评论(第一条):tomasp.net/blog/cannot-return-anonymous-type-from-method.aspx
  • 完全同意,在这里我至少会在框架中使用 Tuple 或类似的预定义类型,但我可能会为这种情况创建一个新类型。
  • 每个人都在说“哦,那是邪恶的”,但为什么呢?它只能在运行时检查,但很多语言都以这种方式工作,比如 Python。这可能是一个可接受的设计决策。无论如何,如果您要从一个对象转换回任何东西,那么无论如何它只是运行时可检查的。那么,如果您要转换回一个字符串或两个字符串,有什么区别呢?
  • 我同意'不应该使用',现在有元组如果你真的懒得写一个小类。
【解决方案2】:

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

您的事件处理程序将如下所示:

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

【讨论】:

  • +1 - 这是 C# 4.0 中的一个不错的选择。在这种情况下,option.Id 将在运行时进行评估。
【解决方案3】:

引用MSDN

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

      【解决方案5】:
      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);
      

      【讨论】:

      • @gsharp。我的用例是对 Jsonresult 进行单元测试,它发送多个已实现类的匿名类型。所以我已经有了 SomeClasses 但想要一个匿名类型来传递 json。这对我来说非常适合谢谢。
      【解决方案6】:

      你可以试试这个:

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

      见:Can't return anonymous type from method? Really?

      【讨论】:

        【解决方案7】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-05-01
          • 2020-04-18
          • 2012-01-20
          • 1970-01-01
          • 2011-04-19
          • 1970-01-01
          相关资源
          最近更新 更多