问题很简单:我正在使用反射来获取值。然后,如果它是一个 struct
,我将调用一个方法 FooStruct
,否则 FooClass
:
Type type = x.GetType();
foreach (var fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
var val = fieldInfo.GetValue(value);
object obj = type.IsValueType ? val.FooStruct() : val.FooClass();
fieldInfo.SetValue(x, obj);
}
问题是 FooStruct
有一个约束:
public static T FooStruct<T>(this T value) where T : struct
{
//...
}
所以问题是:是否可以为包含装箱结构实例而不进行反射的对象调用具有 struct
约束的方法?
最佳答案
我很乐意被另一个答案证明是错误的,但我认为如果不更多地进行反射(reflection),这是不可能的。请参阅下文进一步了解让我怀疑这一点的原因。有关基于反射的解决方案,请参阅答案的结尾。
实用建议:我会简单地放弃对你的 FooStruct
的约束和 FooClass
方法,另外:
要么让它们成为非通用的,要么接受类型为
object
的参数(这就是val
被声明为,无论如何)。如果这些方法只被传递,那么让这些方法成为通用的就没有任何优势object
;或投
val
来自object
至T
在调用之前FooStruct
/FooClass
.
为什么似乎无法完成您的要求?您正在尝试转换静态类型的表达式 object
(即 val
)到静态类型的东西 <T> where T : struct
或 <T> where T : class
(为了在这样的 T
上调用相应的扩展方法)。也就是说,您正试图在 foreach
中动态引入一个新的类型变量。环形。不幸的是,引入类型变量的唯一方法是提前声明它,即作为一些泛型类型参数 T
在方法的签名中;然后,不是您的方法内部的代码可以选择它代表的实际类型——是调用的代码决定T
.
基于反射的解决方案:
// determine which method ought to be called based on `val`'s run-time type.
// (for C# 6 and later, use the `nameof` operator instead of hard-coding method names)
Type type = val.GetType();
string fooName = type.IsValueType ? "FooStruct" : "FooClass";
// bind to the generic method and supply the type argument for it:
// (I'm assuming that your extension methods are defined in `FooMethodsClass`.)
MethodInfo fooOpen = typeof(FooMethodsClass).GetMethod(fooName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
MethodInfo foo = fooOpen.MakeGenericMethod(new Type[] { type });
// invoke the generic (extension) method with `val` as the `this` argument:
foo.Invoke(null, new object[] { val });
关于c# - 如何调用具有结构约束的方法到未知结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27965803/