2009-09-14 22 views
5

Wdrażam ogólny interfejs (konkretnie, iqueryprovider). w pewnym momencie, jestem zmuszony zwrócić wynik rodzajowy, że muszę się z jakimś wewnętrznym interfejsem:Ogólne ograniczenia i interfejsy typów typów

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

gdzie something.Foo jest

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

to oczywiście wieje ponieważ zdefiniowany zewnętrznie TResult nie ma takich samych ograniczeń typu jak wewnętrznie zdefiniowane T. pytanie: czy istnieje sposób na uprzyjemnienie TResult dla Foo? czy mogę w jakiś sposób jawnie przetestować te dwa warunki i zmusić zmienną typu?

Odpowiedz

2

można spróbować coś takiego:

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 
    } 
} 
+2

* wzdycha *, podczas gdy to działa, to cholernie nieprzyjemne, zwłaszcza w kodzie na poziomie framework. – kolosy

+0

Skończyłem w ten sposób. Nie jestem zwolenniczką miękkiej zależności od metody, ale bije ona porzucając ograniczenia i wciąż wykonując odwołania do innych rzeczy, które zrobiła metoda wewnętrzna. – kolosy

0

Trzeba będzie dodać ograniczenia typu do metoda rodzajowa:

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

która nie działa, ponieważ ta sygnatura metody jest zdefiniowana w interfejsie, którego nie kontroluję. dodanie tych ograniczeń sprawia, że ​​ta metoda jest przeciążeniem implementacji interfejsu. – kolosy

1

Nie. Jeśli TResult nie ma na to ograniczeń, może to być jakaś stara rzecz. Jeśli twoja metoda pomocnika nie może zająć niczego starego, wtedy musisz uzyskać lepszą metodę pomocnika. Interfejs wymaga dostarczenia większej liczby usług, niż może zapewnić pomocnik, dlatego będziesz musiał wykonać pracę, aby zapewnić tę usługę.

0

Ała ... masz problem. Nie ma sposobu na wywołanie czegoś.Foo(), ponieważ nie masz typu, który jest zgodny. można „włamać się” wokół tego poprzez stworzenie „otoki” typ, który jest kompatybilny do wywołania Foo(), a następnie „rozpakować”:

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: Odbicie odpowiedź może być lepszym rozwiązaniem, czy zadziała.

+0

Tak, to odmiana odpowiedzi na inne odbicie ... – kolosy

0

Zmień Foo, aby sprawdzić ograniczenia w czasie wykonywania:

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

Te ogólne ograniczenia są sprawdzane w czasie kompilacji, więc nie może być oparta na warunkach run-time.

Powiązane problemy