检查类型是否具有无参数构造函数,以便强制转换它并调用需要具有: new()
约束的无参数构造函数的方法?
仅检查此处回答的公共无参数类型是不够的,因为它不允许调用目标方法。
目标是具有以下逻辑,其中IInteresting
对象不实现公共无参数构造函数,需要在调用Save1
之前进行转换:
public interface IInteresting { }
public void Save<T>(T o) {
var oc = o as (new()); /* Pseudo implementation */
if (oc != null) {
this.Save1(oc);
}
else {
var oi = o as IInteresting;
if (oi != null) {
this.Save2(oi);
}
}
}
private void Save1<T>(T o) where T : new() {
//Stuff
}
private void Save2<T>(IInteresting o) {
//Stuff to convert o to a DTO object with a public parameterless constructor, then call Save1(T o)
}
当然,如果我能Save1
并Save2
共享可以解决问题的相同签名,但我找不到一种方法,因为以下内容不会编译(在Routine
中,Save
将调用第一个实现而不是第二个):
public void Routine<T>(T o) {
var oi = o as IInteresting;
if (oi != null) {
this.Save(oi);
}
}
private void Save<T>(T o) where T : new() {
//Stuff
}
private void Save<T>(IInteresting o) {
//Stuff to convert o to a DTO object with a public parameterless constructor, then call Save(T o)
}
根据您的评论,我想您有一个未知类型的对象,您希望将其传递给一个泛型函数,该函数要求传递的对象是泛型类型参数,该参数必须具有无参数构造函数。因此,就目前而言,我们可以假设您的函数Save1<T>(T)
您的问题中是该函数,不是由您编写的,不可能更改。
对此的解决方案是使用反射进行调用:
- 使用
Type.GetMethod
查找您尝试调用的方法的MethodInfo
。 - 通过使用
MakeGenericMethod
指定类型参数,构造无参数构造函数类型的方法MethodInfo
。 - 通过调用
MethodInfo.Invoke
方法调用该方法。
另一种可能的解决方案,取决于您在private void Save<T>(T o) where T : new()
中执行的操作ICloneable
是使用接口。或者介绍一下你的(正如我所说,这取决于Save
的内容):
interface IConstructible
{
object Construct();
}
并具有:
private void Save1<T>(T o) where T : ICloneable {
当然,这只是一种解决方法 - O. R. Mapper的答案给出了唯一的直接解决方案。
using System.Reflection;
public static class Generics {
public static void T0<T> ( T obj ) where T : new () {
Console.WriteLine ( "{0} {1}", obj, obj.GetType () );
}
public static void T1<T> ( T obj ) {
MethodInfo mi = GenericMethodInfo ( typeof ( Generics ), "T0", typeof ( T ) );
mi.Invoke ( null, new object[] { obj } );
}
public static MethodInfo GenericMethodInfo ( Type classType, string methodName, Type genericType ) {
return classType.GetMethod ( methodName ).MakeGenericMethod ( genericType );
}
}
Generics.T0 ( 123 );
Generics.T1 ( 123 );
// Impossible.. Generics.T0 ( "12345" );
Generics.T1 ( "12345" );