为什么不能从泛型约束中隐式推断出 this 的类型转换?
Why can't the type conversion of `this` be implicitly inferred from the generic contraint?
我有以下 class:
public class Item<TItem>
where TItem : Item<TItem>
{
void GetReference()
{
TItem item = this;
}
}
此处 TItem item = this;
生成编译器错误 "can't convert Item<TItem>
implicitly to TItem
"。
但是为什么我们需要在这里进行转换呢?我们已经定义了约束where TItem : Item<TItem>
,所以可以认为根本不需要转换,因为这两种类型是相同的,不是吗?
顺便说一句,显式转换可用。这也在编译器错误中说明。
那是因为你的 class 是类型 Item<TItem>
而不是 TItem
。你可以;
Item<TItem> item = this;
示例有点令人费解。将其放入上下文 TItem item = this;
解决尝试做
Item<TItem> item = new Item<Item<TItem>>();
因为这样不安全。考虑:
public class GoodItem : Item<GoodItem>
{
// No problem
}
public class EvilItem : Item<GoodItem>
{
// GetReference body would be equivalent to
// GoodItem item = this;
// ... but this *isn't* a GoodItem, it's an EvilItem!
}
EvilItem
毫无问题地满足 TItem
的约束 - GoodItem
确实源自 Item<GoodItem>
.
无法表达声明的 class 和类型参数之间的关系,而这正是您真正想要的。
因为每个 TItem
都是 Item<TItem>
(由 where 约束声明),但反之则不然。
TItem
可能比 Item<TItem>
更衍生,this
也是如此,TItem
可能是苹果,this
可能是橙子。所以编译器阻止了赋值。
目前在 c# 中无法声明类型参数必须匹配继承 class 本身的类型。
有两种常见的方法可以解决这个问题。首先使用显式转换
TItem GetReference() => (TItem) this;
你的工作是确保继承 class 使用正确的类型参数,否则如果你尝试使用此方法,你可能会遇到运行时异常。
第二种方法是使用 class 本身的 return 类型。这是安全的(没有运行时异常)但没有任何类型的派生 classes 合同。也就是说,您应该确保为每个派生的 class.
编写此方法
Item<TItem> GetReference() => this;
现在您可以在派生的 classes 中隐藏此方法。
new Derived GetReference() => this; // public class Derived : Item<Derived>
请注意,此功能已在 GitHub c# 存储库中请求,https://github.com/dotnet/csharplang/issues/252
你只需要等待 c# 团队添加此功能:)
我有以下 class:
public class Item<TItem>
where TItem : Item<TItem>
{
void GetReference()
{
TItem item = this;
}
}
此处 TItem item = this;
生成编译器错误 "can't convert Item<TItem>
implicitly to TItem
"。
但是为什么我们需要在这里进行转换呢?我们已经定义了约束where TItem : Item<TItem>
,所以可以认为根本不需要转换,因为这两种类型是相同的,不是吗?
顺便说一句,显式转换可用。这也在编译器错误中说明。
那是因为你的 class 是类型 Item<TItem>
而不是 TItem
。你可以;
Item<TItem> item = this;
示例有点令人费解。将其放入上下文 TItem item = this;
解决尝试做
Item<TItem> item = new Item<Item<TItem>>();
因为这样不安全。考虑:
public class GoodItem : Item<GoodItem>
{
// No problem
}
public class EvilItem : Item<GoodItem>
{
// GetReference body would be equivalent to
// GoodItem item = this;
// ... but this *isn't* a GoodItem, it's an EvilItem!
}
EvilItem
毫无问题地满足 TItem
的约束 - GoodItem
确实源自 Item<GoodItem>
.
无法表达声明的 class 和类型参数之间的关系,而这正是您真正想要的。
因为每个 TItem
都是 Item<TItem>
(由 where 约束声明),但反之则不然。
TItem
可能比 Item<TItem>
更衍生,this
也是如此,TItem
可能是苹果,this
可能是橙子。所以编译器阻止了赋值。
目前在 c# 中无法声明类型参数必须匹配继承 class 本身的类型。
有两种常见的方法可以解决这个问题。首先使用显式转换
TItem GetReference() => (TItem) this;
你的工作是确保继承 class 使用正确的类型参数,否则如果你尝试使用此方法,你可能会遇到运行时异常。
第二种方法是使用 class 本身的 return 类型。这是安全的(没有运行时异常)但没有任何类型的派生 classes 合同。也就是说,您应该确保为每个派生的 class.
编写此方法Item<TItem> GetReference() => this;
现在您可以在派生的 classes 中隐藏此方法。
new Derived GetReference() => this; // public class Derived : Item<Derived>
请注意,此功能已在 GitHub c# 存储库中请求,https://github.com/dotnet/csharplang/issues/252
你只需要等待 c# 团队添加此功能:)