2012-08-23 6 views
5

Ich stoße auf ein generisches Problem, während ich an einem generischen Dependency-Injection-Handler (einem Basis-Service-Locator) arbeite.Wie können Sie T in eine Klasse umwandeln, die einer "Where T: class" -Beschränkung entspricht?

Edit 1 (für Klarheit)

Okay, so tatsächlich SimpleInjector als DI-Resolver ich bin und es hat die Klasse Einschränkung auf es ist GetInstance Methode, ist so hier einige komplettere Code:

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

Edit 2 - endgültiger Code, da es in den Kommentaren seltsam aussieht:

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

Vielleicht, wenn wir mehr über wussten, warum Sie daran interessiert sind diese dabei, abgesehen von einer Rückkehr null Beispiel ...? Könnte ein besserer Weg sein, es zu strukturieren. –

+0

Bitte beachten Sie Edit 1 für, warum ich dies tun möchte. – Laurence

Antwort

1

Sie können eine weitere Hilfsmethode verwenden? Sie finden Testklasse unter

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

Das funktioniert tatsächlich, danke. Ich vergaß zu T Casting: 'public T GetInstance () { versuchen { if (typeof (T) .IsClass) { return (T) _container.GetInstance (typeof (T)); } } catch (ActivationException aEx) { Rückkehrstandard (T); } } ' – Laurence

1

Die kurze Antwort ist, dass Sie das nicht tun können, zumindest nicht direkt. Der Compiler müsste viel arbeiten, um absolut zu garantieren, dass T immer eine Klasse in Ihrer Situation sein wird, so dass Sie ihn nicht als generischen Typparameter übergeben können, ohne die gleiche Typbeschränkung auf GetEvenMoreGenericInstance anzuwenden.

Sie können dies durch Reflektion erreichen oder eine nicht generische Überladung von GetInstance erstellen, die einen Type als Parameter verwendet. Ich würde die Type-Parameter-Option empfehlen oder Ihren Code vollständig umstrukturieren, um den Aufruf dieser Methode zu vermeiden.

0

Sie Reflektion verwenden könnte eine Variante von GetInstance zu finden, die dann die entsprechende man nennen.

Das folgende Beispiel macht Anrufe auf statische Methoden, aber man kann es erweitern:

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

Ich mag die Verwendung von Reflektion :) – Laurence

Verwandte Themen