如何将T转换为类以匹配“where T:class”约束?

时间:2012-08-23 13:09:29

标签: c# generics constraints

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

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

3 个答案:

答案 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>();
        }
    }
}