2012-08-23 6 views
5

Występuje problem generyczny podczas pracy nad ogólnym program obsługi Dependency Injection (podstawowy lokalizator usług).W jaki sposób można rzucić T na klasę, aby dopasować ograniczenie "tam, gdzie: klasa"?

Edycja 1 (dla jasności)

Ok więc ja rzeczywiście przy SimpleInjector jako rezolwerem DI i ma klasę ograniczenia na jego metoda GetInstance, więc tutaj jest trochę bardziej kompletny kod:

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

Edycja 2 - ostateczny kod, ponieważ wygląda dziwnie w komentarzach:

public T GetInstance<T>() 
    { 
    try 
    { 
     if(typeof(T).IsClass) 
     { 
      return (T) _container.GetInstance(typeof(T)); 
     } 
    } 
    catch(ActivationException aEx) 
    { 
     return default(T); 
    } 
    } 
+5

Może gdybyśmy wiedzieli więcej o tym, dlaczego jesteś zainteresowany w ten sposób, oprócz powracającego zerowej przykład ...? Może to być lepszy sposób na jej ukształtowanie. –

+0

Zobacz edycję 1, dlaczego chcę to zrobić. – Laurence

Odpowiedz

1

Możesz użyć jeszcze jednej metody pomocnika? Proszę znaleźć klasę testową poniżej

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); 
    } 
} 
+0

To faktycznie działa, dzięki. Zapomniałam o przesyłanie T: 'publicznego T GetInstance () { spróbować { if (typeof (T) .IsClass) { powrotny (T) _container.GetInstance (typeof (T)); } } catch (ActivationException aEx) { Zwrot domyślny (T); } } ' – Laurence

1

Krótka odpowiedź brzmi, że nie możesz tego zrobić, przynajmniej nie bezpośrednio. Kompilator musiałby wykonać wiele pracy, aby absolutnie zagwarantować, że T zawsze będzie klasą w twojej sytuacji, więc nie pozwoli ci przekazać go jako ogólnego typu parametru bez zastosowania tego samego ograniczenia typu do GetEvenMoreGenericInstance.

Można to osiągnąć poprzez odbicie lub utworzyć nietypowe przeciążenie GetInstance, które przyjmuje parametr Type jako parametr. Polecam opcję parametru Typ lub całkowicie zrestrukturyzuję twój kod, aby wyeliminować konieczność wywoływania tej metody.

0

można użyć refleksji znaleźć wariant GetInstance, następnie wywołać odpowiednią.

Poniższy przykład dzwoni do metod statycznych, ale można ją przedłużyć:

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

Podoba mi się użycie refleksji :) – Laurence