【发布时间】:2018-11-23 09:37:04
【问题描述】:
假设我有一个方法:
public void ExampleMethod<T>(T x) where T : struct // or new()
{
// example usage, similar to what's actually happening
var z = (T)Enum.Parse(typeof(T), privateFieldOfTypeString);
// do something depending on values of x and z
// possibly using other methods that require them being enums
// or in case of the new() constraint:
// var t = new T() and do something together with x
}
我想按如下方式使用它:
public void CallerMethod<S>(S y)
{
if (typeof(S).IsEnum) // or some other invariant meaning that `S` is "new()able"
{
ExampleMethod(y); // won't compile
}
}
所以,在运行时我知道S 满足ExampleMethod<T> 的约束。我知道可以使用反射来调用它,类似于:
this
.GetType()
.GetMethod(nameof(ExampleMethod<object>))
.MakeGenericMethod(typeof(S))
.Invoke(this, new object[] { y });
没有反射可以吗?
注意:这是来自真实示例的简化代码,显然我无法控制这些方法的签名,因此答案是“将约束添加到 CallerMethod”和“从ExampleMethod中删除约束是无效的。
是的,整个事情都应该重新设计,这样整个问题就不会出现了。但在现实生活中,“整个事情”往往太大、太耦合、太冒险而无法重写。一些需求以一种意想不到的方式发生了变化 - 因此明显的代码异味,我试图通过将其隐藏在一个看起来很讨厌的地方来最小化它。
【问题讨论】:
-
你知道
S满足ExampleMethod<T>的约束,但编译器不满足。如果可能,您需要将约束添加到CallerMethod。这就是泛型成员的本质。 -
@Nkosi 继续你的表述:问题是“如何告知编译器这个事实”。泛型之外的一个类比是强制转换 - 您告诉编译器您知道特定变量属于特定类型。
-
强制转换是运行时
-
@BartoszKP 对于这两种方法如何相互交互的简化示例,我不知所措。是否可以提供一些上下文来了解预期目标,以便将其排除为XY problem。
-
@Nkosi 我不这么认为。细节无关紧要,这就是我坚持使用这两种方法的事实,我需要从另一种方法中调用一个。它们位于不同的类型和不同的组件上,但这些细节确实无关紧要。我完全知道整个事情应该重新设计,这样这个问题就不会出现了。恕我直言,这个问题很清楚 - 是否有可能,如果是的话 - 如何?可能的预期答案很容易想象:“不,不可能,受语言规则/编译器限制”或“是的,有可能,就是这样”。
标签: c# generics generic-constraints