5

我在处理通用依赖注入处理程序(基本服务定位器)时遇到了泛型问题。

编辑 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 );
     }
  }
4

3 回答 3

1

简短的回答是你不能这样做,至少不能直接这样做。编译器必须做很多工作才能绝对保证 T 在您的情况下始终是一个类,因此它不会让您将其作为泛型类型参数传递,而不对 GetEvenMoreGenericInstance 应用相同的类型约束。

您可以通过反射来完成此操作,或者创建一个以 Type 作为参数的非泛型 GetInstance 重载。我建议使用 Type 参数选项,或者完全重组代码以消除调用此方法的需要。

于 2012-08-23T13:26:05.007 回答
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 );
  }
}
于 2012-08-23T13:26:16.703 回答
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>();
        }
    }
}
于 2012-08-23T13:38:19.627 回答