考虑一下:
var me = new { FirstName = "John", LastName = "Smith" };
这很好,因为我们可以这样做:
Console.WriteLine("{0} {1}", me.FirstName, me.LastName);
但是我们不能这样做:
public T GetMe() { return new { FirstName = "John", LastName = "Smith" }; }
因为我们不知道T的类型
我们可以这样做:
public object GetMe() { return new { FirstName = "John", LastName = "Smith" }; }
但是我们必须使用反射检查对象的属性才能访问它们:
var p = new Prog(); object o = p.GetMe(); Type t = o.GetType(); foreach (var prop in t.GetProperties()) { Console.WriteLine(prop.Name + ": " + prop.GetValue(o, null)); }
然而,如果我们可以命名一个匿名类型,我们定义它呢?当然它不再是匿名的,但它比普通的类定义更简洁和可维护.
考虑一下:
public Person GetMe() { return new public class Person { FirstName = "John", LastName = "Smith" }; }
这样做的好处是可以从方法返回复杂Linq查询的结果,而无需显式定义类.
考虑这个相对复杂的Linq查询:
Listlist = new List (); var query = from number in list select new { Number = number, Square = number*number, Absolute = Math.Abs(number), Range = Enumerable.Range(0, number) };
而不是像这样定义一个类:
public class MyNumbers { public int Number { get; set; } public int Square { get; set; } public int Absolute { get; set; } public IEnumerableRange { get; set; } }
为了从一个方法返回查询变量,我们可以改为:
Listlist = new List (); return from number in list select new public class MyNumbers { Number = number, Square = number*number, Absolute = Math.Abs(number), Range = Enumerable.Range(0, number) };
BFree.. 13
实际上,你可以做一个"hack"来从一个方法中获取一个匿名类型.考虑一下:
public object MyMethod() { var myNewObject = new { stringProperty = "Hello, World!", intProperty = 1337, boolProperty = false }; return myNewObject; } public T Cast(object obj, T type) { return (T)obj; }
你现在可以这样做:
var obj = MyMethod(); var myNewObj = Cast(obj, new { stringProperty = "", intProperty = 0, boolProperty = false });
myNewObj现在将是与匿名类型相同类型的对象.
实际上,你可以做一个"hack"来从一个方法中获取一个匿名类型.考虑一下:
public object MyMethod() { var myNewObject = new { stringProperty = "Hello, World!", intProperty = 1337, boolProperty = false }; return myNewObject; } public T Cast(object obj, T type) { return (T)obj; }
你现在可以这样做:
var obj = MyMethod(); var myNewObj = Cast(obj, new { stringProperty = "", intProperty = 0, boolProperty = false });
myNewObj现在将是与匿名类型相同类型的对象.
您需要的语言功能是:
public var GetMe() { return new { FirstName = "John", LastName = "Smith" }; }
也就是说,var
作为方法返回类型是有效的,编译器会根据返回的内容推断出实际类型.然后,您必须在呼叫站点执行此操作:
var me = GetMe();
任何两个具有相同类型成员的匿名类型都是相同的类型,因此如果您编写其他函数返回相同的模式,它们将具有相同的类型.对于任何类型A和B,其中B具有A的成员的子集,则A与B分配兼容(B类似于A的基类).如果你写道:
public var GetMeFrom(var names) { return new { FirstName = names["First"], LastName = names["Last"] }; }
编译器将有效地将其定义为具有两个类型参数的泛型方法,T1
即名称的类型,并且T2
是索引器返回的T1
接受字符串的类型.T1
将被约束,以便它必须有一个接受字符串的索引器.在调用站点,您只需传递任何具有接受字符串的索引器并返回您喜欢的任何类型的内容,这将确定返回的类型FirstName
和LastName
类型GetMeFrom
.
因此,类型推断将为您解决所有这些问题,自动捕获代码中可发现的任何类型约束.
恕我直言,根本问题与匿名类型无关,但声明一个类太冗长了.
选项1:
如果你可以声明一个这样的类:
public class MyClass { properties={ int Number, int Square, int Absolute, IEnumerableRange } }
或者其他一些类似的快速方式(比如元组示例)那么你不会觉得需要用匿名类型来做hacky事情只是为了保存一些代码.
当'编译器即服务'到达C#5时,希望他们能够很好地集成它,我们将能够使用元编程来干净地解决这些问题.派对就像是1958年!
选项2:
或者,在C#4中,你可以只传递一个匿名类型,dynamic
并避免所有的转换.当然,如果重命名变量等,这会打开运行时错误.
选项3:
如果C#以与C++相同的方式实现泛型,那么你可以将匿名类型传递给一个方法,只要它有正确的成员,它就会编译.您将获得静态类型安全的所有好处,并没有任何缺点.每当我输入where T : ISomething
C#时,我都很生气他们没有这样做!