是否可以将泛型参数限制为当前对象的子类型?
这是我刚刚遇到的一个有趣的问题。可以使用扩展方法来做我想做的事情,但似乎不可能用类本身的成员来做。
使用扩展方法,可以编写一个具有如下所示签名的方法:
public static void DoStuff<T>(this T arg1, T arg2)
这强制两个参数都是您所关心的调用它的任何类型。当与委托一起使用时,这会变得更有用。
public static void DoStuff<T>(this T arg1, Action<T> arg2)
但是我无法让它与成员一起工作。不存在这样的约束:
public void DoStuff<T>(T arg1) where T : typeof(this)
如果这确实有效,那么您可以像这样在基类上定义一个方法(我使用了流,因为它们是 .NET 中的内置层次结构):
class Stream
{
public void DoStuff<T>(T stream) where T : this
{
}
}
然后在子类上则不会可以这样称呼它:
ByteStream bs = new ByteStream()
bs.DoStuff(new Stream()) // Error! DoStuff() should be inferred as DoStuff<ByteStream>()
有什么办法可以做到这一点吗?我相信从参数自动推断类型和扩展方法是语法糖。这可能就是它起作用的原因;因为扩展方法被静态调用替换,从而允许推断类型。
我问这个问题是因为我试图将扩展方法移动到公共基类中,并且在不添加类型信息的情况下无法编译它。
澄清一下。这不仅仅是添加 where T : MyType
的情况,因为如果我创建一个继承自 MyType
的名为 MySubType
的类型,我将能够在 MySubType
实例上调用 DoStuff
并传递 MyType
作为参数。这也意味着,在需要 Action
的情况下,如果不先进行强制转换,我将无法调用 MySubType
的方法。
Here's an interesting problem that I have just come across. It is possible to do what I want using extension methods, but does not seem possible to do with members of the class itself.
With extension Methods it is possible to write a method that has a signature that looks like this:
public static void DoStuff<T>(this T arg1, T arg2)
this enforces that both arguments are of whatever type you care calling it on. This becomes more useful when used with delegates.
public static void DoStuff<T>(this T arg1, Action<T> arg2)
However I cannot get this to work with members. There is no such constraint as this:
public void DoStuff<T>(T arg1) where T : typeof(this)
if this did work then you could define a method on your base class like this (I've used streams as they are a built in hierarchy in .NET):
class Stream
{
public void DoStuff<T>(T stream) where T : this
{
}
}
and then on a subclass it would not be possible to call it like this:
ByteStream bs = new ByteStream()
bs.DoStuff(new Stream()) // Error! DoStuff() should be inferred as DoStuff<ByteStream>()
Is there any way of doing this? I believe that automatically inferring the types from the arguments, and extension methods are syntactic sugar. And that is probably why it works; because the extension methods are replaced by static calls, which then allow the type to be inferred.
I ask because I am trying to move an extension method into a common base class, and cannot get it to compile without adding the type information.
To clarify. This isn't a case of just adding where T : MyType
because if i create a type called MySubType
that inherits from MyType
I will be able to call DoStuff
on an instance of MySubType
and pass a MyType
as the parameter. This also means that in the case where it takes an Action<T>
I will be unable to call methods of MySubType
without casting first.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
有趣的是,规则允许您使用扩展方法而不是常规实例方法来执行此操作。
你的“typeof(this)”约束实际上应该是“this.GetType()”。 “typeof(this)”没有任何意义; typeof 采用类型,而不是任意表达式。
一旦你意识到这一点,那么我们不能做这样的约束的原因就会变得更加清楚。 编译器总是检查约束,但显然“this.GetType()”直到运行时才能确定。这意味着如果我们有这个功能,那么我们就会在运行时在类型系统中引入一个故障点:
你不能将老虎与长颈鹿交配,但是编译器可以在程序中的哪里检测到这一点?无处。 x1 和 x2 的运行时类型直到运行时才知道,因此在此之前无法检测到约束违规。
我们讨厌这样。拥有一个在任何地方都没有强制转换的程序,即使在经过编译器彻底检查之后,仍然可能因类型系统违规而失败,这确实很糟糕。数组协方差就是这样一种情况,因为我们支持数组协方差,所以我们有时不仅会通过编译器传递一个损坏的程序,然后崩溃,而且我们还必须减慢对每个引用类型数组的每次写入,只是为了仔细检查我们没有违反类型系统。这太糟糕了,我们不想在类型系统中添加更多运行时故障点。
这就是为什么我们在 C# 4 中仔细设计新的变体功能,以确保它们始终是类型安全的。 (除非数组上的现有变体转换不是类型安全的,并且将继续不是类型安全的。)我们希望确保编译器可以在编译时检查所有约束是否违反,而不是必须吐出运行时执行的新代码检查可能会意外失败。
How interesting that the rules allow you to do this with extension methods but not with regular instance methods.
Your "typeof(this)" constraint really should be "this.GetType()". "typeof(this)" doesn't make any sense; typeof takes a type, not an arbitrary expression.
And once you realize that then the reason why we cannot do such a constraint becomes more clear. Constraints are always checked by the compiler, but clearly "this.GetType()" cannot be determined until runtime. Which means that if we had that feature, then we'd introduce a point of failure in the type system at runtime:
You cannot mate a Tiger with a Giraffe, but where in the program can the compiler detect that? Nowhere. The runtime types of x1 and x2 are not known until runtime, and so the constraint violation cannot be detected until then.
We hate that. It really sucks to have a program with no casts anywhere that nevertheless can fail with type system violations, even after having been thoroughly checked by the compiler. Array covariance is just such a case, and because we support array covariance, not only do we sometimes pass a broken program through the compiler that then crashes, we have to slow down every write to every array of reference type just to double-check that we're not violating the type system. It's awful, and we don't want to add more points of runtime failure into the type system.
That's why we're carefully designing the new variance features in C# 4 to ensure that they are always typesafe. (Except insofar as existing variant conversions on arrays are not typesafe and will continue to be not typesafe.) We want to make sure that the compiler can check all the constraints for violation at compile time, rather than having to spit new code that does runtime checks that can fail unexpectedly.
我认为您只需在末尾指定类型就可以做到这一点。
我目前正在解决方案中执行此操作,但 YourType 是一个接口。我认为你可以通过具体的课程来做到这一点。
I think you may be able to do it by just specifying the type on the end.
I am doing that currently in a solution but the YourType is an interface. I think you can do it with a concrete class.
根据您的澄清,我认为实现此目的的唯一方法是使您的基类通用。这有点笨拙,但应该可以满足您的需要。
Following your clarification, I think the only way to achieve this is to make your base class generic. It's a bit clumsy, but should do what you need.
将其更改为:
这样您只能使用从 BaseType 继承的类型 T
Change it to this:
That way you can only use type T that inherit from your BaseType
只需使用基类名称作为约束。
Just use the base class name as the constraint.