我想知道为什么在非泛型类中不能像编写泛型方法那样编写泛型属性。例如:
public interface TestClass
{
IEnumerable<T> GetAllBy<T>(); //this works
IEnumerable<T> All<T> { get; } //this does not work
}
我读了@Jon Skeet的回答,但它只是一个陈述,很可能在规范的某个地方已经有了。
我的问题是为什么会这样?这种限制避免了哪些问题?
我想知道为什么在非泛型类中不能像编写泛型方法那样编写泛型属性。例如:
public interface TestClass
{
IEnumerable<T> GetAllBy<T>(); //this works
IEnumerable<T> All<T> { get; } //this does not work
}
我读了@Jon Skeet的回答,但它只是一个陈述,很可能在规范的某个地方已经有了。
我的问题是为什么会这样?这种限制避免了哪些问题?
从技术上讲,CLR仅支持泛型类型和方法,而不支持属性,因此问题是为什么它没有添加到CLR中。答案很可能是“它被认为不能带来足够的好处来抵消成本”。
但更根本的是,它被认为没有带来任何好处,因为在语义上没有意义将属性参数化为类型。一个Car
类可以有一个Weight
属性,但是拥有一个Weight<Fruit>
和一个Weight<Giraffe>
属性是没有意义的。
Weight<Fruit>
没有意义。对于每个功能,您都可以构造一个愚蠢的示例,这并不意味着该功能根本没有意义。在这种情况下,请考虑Weight<Kilogram>
,它确实有意义(或者请参见我在问题下的另一个示例)。 - BartoszKP这篇来自Julian Bucknall的通用属性博客文章是一个相当不错的解释。本质上,它是一个堆分配问题。
collection.OfType<Blah>
。但实际上,必须使用方法collection.OfType<Blah>()
,即使它不需要参数。 - munificent我的猜测是它可能存在一些让语法模糊的棘手问题。一时之间,这似乎有点棘手:
foo.Bar<Baz>=3;
这应该解析为:
foo.Bar<Baz> = 3;
或者:
foo.Bar < Baz >= 3;
M(a<b,c>(d+1))
与M(a < b, c > (d+1))
的区别,甚至比你举的例子更不刻意),并且已经明确决定采取破坏性变更。 - Timwi我做了类似的东西。 它可以在运行时进行类型检查。
public class DataPackage
{
private dynamic _list;
public List<T> GetList<T>()
{
return (List<T>)_list;
}
public void SetList<T>(List<T> list)
{
_list = list;
}
public string Name { get; set; }
}
我认为不使用自动getter/setter说明为什么在类级别没有定义"T"是不可能的。
尝试编码,自然而然的做法是这样的:
IEnumerable<T> _all;
IEnumerable<T> All
{
get { return _all; }
}
因为您的领域使用了"T",所以" T "需要在类上,CLR 才知道"T"是什么。
当您使用方法时,可以延迟定义"T",直到实际调用该方法。但是对于字段/属性,"T"需要在一个地方声明,在类级别。
一旦在类上声明了T,创建属性就变得非常容易。
public class TestClass<T>
{
IEnumerable<T> All { get; }
}
用法:
var myTestClass = new TestClass<string>();
var stuff = myTestClass.All;
就像方法中的“T”类型参数一样,您可以等到实例化TestClass时再定义“T”的具体含义。
class Figure { public ColorT Color<ColorT> { get { ... } } ... }
(可能对ColorT
有一些约束)以返回所需颜色空间中的颜色。或者使用不同单位的量来参考您的示例。 - BartoszKP<Giraffe>
显然是一个参数 - 具体来说是泛型类型参数。 - Roman StarkovWeight<Giraffe>
没有意义。我指出,这同样适用于通用方法,因此这不能成为没有通用属性的明智理由。 - BartoszKP