我在处理通用依赖注入处理程序(基本服务定位器)时遇到了泛型问题。
编辑1(为清晰起见)
好的,所以我实际上使用SimpleInjector作为DI解析器,它对它的GetInstance方法有类约束,所以这里有一些更完整的代码:
public T GetInstance<T>() where T : class
{
try
{
// works
return _container.GetInstance<T>();
}
catch( ActivationException aEx )
{
return default( T );
}
}
public T GetInstance<T>()
{
try
{
if( typeof( T ).IsClass )
{
// does not work, T is not a reference type
return _container.GetInstance<T>();
}
}
catch( ActivationException aEx )
{
return default( T );
}
}
编辑2 - 最终代码,因为它在评论中看起来很奇怪:
public T GetInstance<T>()
{
try
{
if( typeof( T ).IsClass )
{
return (T) _container.GetInstance(typeof(T));
}
}
catch( ActivationException aEx )
{
return default( T );
}
}
答案 0 :(得分:1)
简短的回答是你不能这样做,至少不是直接的。编译器必须做很多工作才能绝对保证T在您的情况下始终是一个类,因此如果不对GetEvenMoreGenericInstance应用相同的类型约束,它将不允许您将其作为泛型类型参数传递。
您可以通过反射来完成此操作,或者创建一个GetInstance的非泛型重载,它将Type作为参数。我建议使用Type参数选项,或者完全重构代码以消除调用此方法的需要。
答案 1 :(得分:1)
您可以再使用一种辅助方法吗?请在下面找到测试类
public class Test
{
public T GetInstance<T>() where T : class
{
return (T)GetInstance(typeof(T));
}
private object GetInstance(Type type)
{
return Activator.CreateInstance(type);
}
public T GetEvenMoreGenericInstance<T>()
{
if( !typeof( T ).IsValueType )
{
return (T)GetInstance(typeof(T));
}
return default( T );
}
}
答案 2 :(得分:0)
您可以使用反射来查找GetInstance
的变体,然后调用相应的变体。
以下示例调用静态方法,但您可以对其进行扩展:
namespace Scratch
{
internal class Foo
{
// A class to create
}
class Program
{
public static T GetInstance<T>() where T : class, new()
{
return new T(); // Or whatever...
}
public static T CallGeneric<T>(Func<object> f)
{
var method = f.Method;
var converted = method.GetGenericMethodDefinition().MakeGenericMethod(typeof(T));
return (T) converted.Invoke(null, new object[] {});
}
public static T GetEvenMoreGenericInstance<T>()
{
if(!typeof(T).IsValueType)
{
return CallGeneric<T>(GetInstance<object>);
}
return default(T);
}
static void Main( string[] args )
{
var a = GetEvenMoreGenericInstance<int>();
var b = GetEvenMoreGenericInstance<Foo>();
}
}
}