【问题标题】:What's the return type of an anonymous class匿名类的返回类型是什么
【发布时间】:2011-06-25 22:44:54
【问题描述】:

我有一个曾经有一个字符串返回类型的类。现在我发现我需要返回的不仅仅是一个字符串。我正在考虑返回如下内容:

public string Test()
{
  return ( new { ID = 5, Name= "Dave" } );
}

这是否可能,如果可能,那么返回类型是什么?我知道这不是字符串..

【问题讨论】:

  • 如果您创建了匿名object,则返回类型肯定是object

标签: c#


【解决方案1】:

正如其他人所说,这里最好的做法是制作一个名义类型。我建议名义类型与匿名类型具有相同的特征;也就是说,您应该考虑使类型 不可变 并考虑使其表现出 值相等

可以将匿名类型作为对象返回,然后使用各种偷偷摸摸的技术在别处使用返回的实例。您可以将对象强制转换为“动态”(在 C# 4 中),然后使用匿名类型的属性,但这很慢并且缺少编译时类型检查。

您还可以使用“按示例转换”技巧,它确实可以让您进行编译时类型检查。但是,只有当匿名源对象和匿名示例对象来自同一个程序集时,该技巧才有效

static T CastByExample<T>(object source, T example) where T : class
{
    return source as T;
}

static object ReturnsAnonymous() { return new { X = 123 }; }

static void DoIt()
{
    object obj = ReturnsAnonymous();
    var example = new { X = 0 };
    var anon = CastByExample(obj, example);
    Console.WriteLine(anon.X); // 123
}

看看这有多狡猾?我们使用方法类型推断和局部变量类型推断来告诉编译器“这两个东西是同一类型”。这使您可以将匿名类型导出为对象并将其转换回匿名类型。

但您可能不应该这样做;如果您使用这种鬼鬼祟祟的技巧,那么您应该首先简单地定义一个名义类型。另外,就像我说的,这个技巧只有在 examplesource 对象是在同一个程序集中的代码中创建时才有效;两个不同程序集中的两个“相同”匿名类型统一为同一类型。

【讨论】:

    【解决方案2】:

    您返回的对象确实有一个类,但它是匿名的,因此您无法在代码中指定它。您只需将其作为 object 参考返回即可:

    public object Test() {
      return new { ID = 5, Name= "Dave" };
    }
    

    请注意,匿名类型在方法范围之外是未知的,因此反射是访问其属性的唯一方法。

    如果你希望能够方便地使用返回的对象,你应该声明一个类:

    public class TestResult
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }
    
    public TestResult Test() {
        return new TestResult() { ID = 5, Name= "Dave" };
    }
    

    如果适合您的目的,另一种选择是使用现有的类。 KeyValuePair 与您使用的很接近,但是属性当然会被命名为 KeyValue 而不是 IDName

    public KeyValuePair<int, string> Test() {
      return new KeyValuePair<int, string>(5, "Dave");
    }
    

    【讨论】:

    • 不是 100% 正确:从技术上讲,匿名类型的范围是封闭类型,而不仅仅是方法。因此,同一类中的其他方法是已知的。因此,可以使用dynamic 访问这些属性。 :)
    • @Timwi:不,匿名类型的范围是方法。您可以使用dynamic 从任何地方访问匿名对象,范围无关紧要。
    • @Timwi, @Guffa:不,你们都错了;首先,匿名类型在任何地方都没有“作用域”,因为它没有名称,而作用域是可以通过名称访问实体的区域。其次,两个相同匿名类型表现出类型统一的代码单元是当前编译——通常是整个程序集。
    • @Guffa:此外,只有 Reflection 可以用于访问已隐式转换为对象的匿名类型的属性,这是不正确的。您可以通过将对象转换回匿名类型,以另一种方法重新获得匿名类型。您必须使用鬼鬼祟祟的“以身作则”技术,但它可以做到。也就是说,如果您使用这些技巧,您应该首先使用名义类型。
    • @Eric Lippert:好吧,范围可能不是用来形容它的正确术语(实际上我没有在我的回答中使用它)。我的观点是,您可以在方法内部轻松访问匿名类型中的属性,但不能在方法外部访问。
    【解决方案3】:

    这是不可能的,因为匿名类仅在当前上下文中有效。如果你需要返回一个对象,那么你需要创建一个真正的类。

    我假设您意外地将 string 作为返回类型。

    【讨论】:

      【解决方案4】:

      Anonymous type 是直接从object 派生的类类型。

      您可以从方法中将其返回为 object 作为返回类型。 看看this

      【讨论】:

        【解决方案5】:

        不,这是不可能的。您的选择是:

        1. 为返回值定义一个真正的类,
        2. 使用 System.Tuple,或
        3. 用尽参数(可能是最差的选择)。

        【讨论】:

          【解决方案6】:

          您可以为此创建一个结构(或类)。

          public struct IdAndName
          {
              public int Id;
              public string Name;
          
              public IdAndName(int id, string name)
              {
                  ID = id;
                  Name = name;
              }
          }
          

          您也可以使用元组,(但不建议这样做,因为没有命名属性。

          【讨论】:

            【解决方案7】:
            class NewString
            {
                public int ID { get; set; }
                public string Name { get; set; }
            }
            
            public NewString Test()
            {
                return ( new NewString() { ID = 5, Name = "Dave" } );
            }
            

            :)

            【讨论】:

              猜你喜欢
              • 2020-10-29
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-04-21
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多