泛型类型变量限制和接口

时间:2009-09-14 22:06:58

标签: c# generics

我正在实现一个通用接口(特别是iqueryprovider)。在某些时候,我被迫返回一个通用结果,我需要从一些内部接口获取:

public TResult Execute<TResult>(...) {
  return something.Foo<TResult>();
}

其中something.Foo是

public T Foo<T>() where T: MyBaseClass, new() {
  ...
}

这当然会爆炸,因为外部定义的TResult与内部定义的T没有相同的类型限制。问题是:有没有办法让TResult适合Foo?我可以以某种方式明确测试这两个条件并强制类型变量吗?

5 个答案:

答案 0 :(得分:2)

您可以尝试这样的事情:

public TResult Execute<TResult>(...) 
{
  if (typeof(TResult) is MyBaseClass)
  {
      Type mytype = typeof(TResult);
      MethodInfo method = typeof({TypewhereFoo<>IsDeclared}).GetMethod("Foo");
      MethodInfo generic = method.MakeGenericMethod(myType);
      return (TResult)generic.Invoke(this, null);
  }
  else
  {
     // Throw here
  }
}

答案 1 :(得分:1)

不。如果TResult对它没有约束,那么它可以是任何旧的东西。如果你的帮助方法不能采取任何旧的东西,那么你需要一个更好的帮助方法。界面要求您提供比助手提供的服务更多的服务,因此,您将不得不完成提供该服务的工作。

答案 2 :(得分:0)

您必须将类型限制添加到通用方法中:

public TResult Execute<TResult>(...) where TResult: MyBaseClass, new() {
  return something.Foo<TResult>();
}

答案 3 :(得分:0)

哎哟......你有问题。没有办法调用something.Foo(),因为你没有兼容的类型。你可以通过创建一个兼容调用Foo()然后'解包'的“包装”类型来“破解”:

    class MyNastyFix<T> : MyBaseClass
    {
        public T Unwrap()
        {
            //assert that T has the correct base type
            if (!typeof(T).IsSubclassOf(typeof(MyBaseClass)))
                throw new ArgumentException();
            //must use reflection to construct
            T obj = (T)typeof(T).InvokeMember(null, BindingFlags.CreateInstance, null, null, null);
            //cast to a type of MyBaseClass so we can copy our values
            MyBaseClass c = (MyBaseClass)(object)obj;
            c.SomeValue = this.SomeValue;
            return obj;
        }
    }

    public static TResult Execute<TResult>()
    {
        return something.Foo<MyNastyFix<TResult>>().Unwrap();
    }

更新:如果有效,反思答案可能是更好的方法。

答案 4 :(得分:0)

更改Foo以在运行时检查约束:

public T Foo<T>() {
    if (!typeof(T).IsAssignableFrom(typeof(MyBaseClass))
        || !typeof(T).GetConstructor(...))
        throw new System.NotImplementedException();
    ...
 }

在编译时检查通用约束,因此它们不能基于运行时条件。