假设我有一个方法:
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
删除约束”无效。
是的,应该对整个事情进行重新设计,以使整个问题根本不会出现。但是,在现实生活中,“整个事情”常常太大,太耦合且太冒险而无法重写。某些要求已经以一种意想不到的方式发生了变化-因此出现了明显的代码气味,我试图通过将其隐藏在一个看起来讨厌的地方来将其最小化。
答案 0 :(得分:3)
您可以使用dynamic
:
if (typeof(S).IsEnum)
{
ExampleMethod((dynamic)y);
}
答案 1 :(得分:1)
如果枚举类型是已知的,尽管很冗长,但一种可能是转换为已知类型。
例如,作为起点,
public void CallerMethod<S>(S y) {
if (typeof(S).IsEnum) {
if (y is KnownEnum) {
var z = (KnownEnum)Enum.Parse(typeof(S), y.ToString());
ExampleMethod(z);
}
if (y is KnownEnum2) {
var z = (KnownEnum2)Enum.Parse(typeof(S), y.ToString());
ExampleMethod(z);
}
//...
}
}
答案 2 :(得分:1)
您可以利用运算符重载;定义CallerMethod
的多个显式版本,所有这些版本都可以成功跟踪ExampleMethod
CallerMethod(Enum1 value) { ExampleMethod(value); }
CallerMethod(Enum2 value) { ExampleMethod(value); }
CallerMethod(Enum3 value) { ExampleMethod(value); }
等
如果有大量的增长类型需要CallerMethod
的版本,则可以编写T4 template来生成具有所有实现的partial
类。
答案 3 :(得分:-2)
在您的特定情况下,您可以将其强制转换为整数。
public void CallerMethod<S>(S y)
{
if (typeof(S).IsEnum)
{
ExampleMethod((int)y);
}
}