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