tags:

views:

255

answers:

5

i'm implementing a generic interface (iqueryprovider, specifically). at some point, i'm forced to return a generic result, that i need to get from some internal interface:

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

where something.Foo is

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

this of course blows up because the externally defined TResult doesn't have the same type restrictions as the internally-defined T. the question: is there a way to make TResult palatable to Foo? can i somehow explicitly test for those two conditions and coerce the type variable?

A: 

You will have to add the type restrictions to your generic method:

public TResult Execute<TResult>(...) where TResult: MyBaseClass, new() {
  return something.Foo<TResult>();
}
Lasse V. Karlsen
that doesn't work, because that method signature is defined on an interface i don't control. adding those restrictions makes that method an overload to the interface implementation.
kolosy
+1  A: 

Nope. If TResult has no constraints on it, then it can be any old thing. If your helper method cannot take any old thing, then you'll need to get a better helper method. The interface requires you to provide more services than your helper can provide, therefore, you're going to have to do the work to provide that service.

Eric Lippert
+2  A: 

You could try something like this:

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
  }
}
Nathan W
*sigh* while that does work, that's damn nasty, especially in framework-level code.
kolosy
i ended up going this way. i'm not a fan of the soft dependency on the method, but it beats dropping the restrictions, and still doing reflection calls on some of the other stuff that the internal method did.
kolosy
A: 

Ouch... you have a problem. There is no way to call something.Foo() since you do not have a type that is compatible. You could 'hack' around this by creating a 'wrapper' type that is compatible to call the Foo() and then 'unwrap' :

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

Update: The reflection answer might be a better approach if that works.

csharptest.net
yup, that's a variation of the other reflection answer...
kolosy
A: 

Change Foo to check the constraints at run-time:

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

The generic constraints are checked at compile-time so they can't be based on run-time conditions.

Mike Stockdale