匿名类的返回类型是什么?

4

我有一个类,原本返回字符串类型。现在我发现需要返回的不仅仅是字符串。我考虑返回类似下面的内容:

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

这种情况是否可能发生,如果是,返回类型会是什么?我知道它不是字符串类型...

如果您创建了一个匿名的 object,那么返回类型肯定是 object - Duncan Howe
7个回答

9
正如其他人所说,这里最好的做法是创建一个名义类型。我建议这个名义类型具有匿名类型的相同特征;即您应该考虑使类型不可变,并考虑使其表现为值相等
可以将匿名类型作为对象返回,然后使用各种巧妙技术在其他地方使用返回的实例。你可以将该对象强制转换为"dynamic"(在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
}

看起来很狡猾,我们使用了方法类型推断和局部变量类型推断来告诉编译器"这两个东西是同一种类型"。这使得您可以将匿名类型导出为对象,并将其强制转换回匿名类型。
但是,您可能不应该这样做;如果您不得不采取这种狡猾的技巧,那么您应该从一开始就定义一个名义类型。另外,正如我所说,这个技巧只有在例子和源对象是在同一个程序集的代码中创建时才有效;在两个不同程序集中的"相同"匿名类型不会合并成为同一种类型。

3

你返回的对象确实有一个类,但它是匿名的,所以你不能在代码中指定它。你只需要将它作为一个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");
}

技术上讲,匿名类型的作用域是限定在封闭类型内部的,而不仅仅是方法。因此,在同一类中的其他方法中也可以使用它。因此,可以使用 dynamic 访问其属性。 :) - Timwi
6
@Timwi,@Guffa:不,你们两个都错了。首先,匿名类型没有名称,因此它在任何地方都不是“作用域”,而作用域是指实体可以通过名称访问的区域。其次,在两个相同的匿名类型表现出类型统一的代码单元是当前编译——通常是整个程序集。 - Eric Lippert
5
@Guffa:另外,只有使用 Reflection 才能访问已经被隐式转换为 object 的匿名类型的属性这一说法是不正确的。你可以通过将 object 强制转换回匿名类型,在另一个方法中重新获取匿名类型。你需要使用“按示例强制转换”的技巧,但这是可行的。不过,如果你要使用这样的技巧,最好一开始就使用一个具名类型。 - Eric Lippert
@Eric Lippert:好的,我应该先检查一下。我以为匿名类型会被编译成私有嵌套类型(就像 lambda 闭包和迭代器块一样),但显然它们被编译成顶级类型,使它们可以被整个程序集访问。 - Timwi
@Timwi:是的,对于私有类来说确实很重要。在作用域之外应该不应该可用。 - Guffa
显示剩余3条评论

0
你可以为此创建一个结构体(或类)。
public struct IdAndName
{
    public int Id;
    public string Name;

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

你也可以使用一个元组<T1, T2>,(但不推荐,因为属性没有命名)。


0
class NewString
{
    public int ID { get; set; }
    public string Name { get; set; }
}

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

:)


0

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

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


0

匿名类型是直接从object派生的类类型。

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


0

不可能。你的选择有:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接