2009-10-22 10 views
25

Mam następujący kod:Generic Metoda Wykonane z typem wykonawczego

public class ClassExample 
{ 

    void DoSomthing<T>(string name, T value) 
    { 
     SendToDatabase(name, value); 
    } 

    public class ParameterType 
    { 
     public readonly string Name; 
     public readonly Type DisplayType; 
     public readonly string Value; 

     public ParameterType(string name, Type type, string value) 
     { 
      if (string.IsNullOrEmpty(name)) 
       throw new ArgumentNullException("name"); 
      if (type == null) 
       throw new ArgumentNullException("type"); 

      this.Name = name; 
      this.DisplayType = type; 
      this.Value = value; 
     } 
    } 

    public void GetTypes() 
    { 
     List<ParameterType> l = report.GetParameterTypes(); 

     foreach (ParameterType p in l) 
     { 
      DoSomthing<p.DisplayType>(p.Name, (p.DisplayType)p.Value); 
     } 

    } 
} 

Teraz wiem, że nie można wykonać doSomething() jest jakiś inny sposób, aby korzystać z tej funkcji?

Odpowiedz

29

Możesz, ale to wymaga refleksji, ale możesz to zrobić.

typeof(ClassExample) 
    .GetMethod("DoSomething") 
    .MakeGenericMethod(p.DisplayType) 
    .Invoke(this, new object[] { p.Name, p.Value }); 

będzie to wyglądać w górnej części zawierającej klasy, uzyskać informacje o metodzie, stworzyć ogólną metodę z odpowiedniego typu, to można zadzwonić Invoke na nim.

+0

Tylko jeden połów, p.Value to ciąg znaków, więc wywołanie zakończy się niepowodzeniem, chyba że p.DisplayType stanie się typem (string). – stevemegson

+1

Szkoda, że ​​to jedyne rozwiązanie, meh. –

+1

Myślę, że możesz użyć dynamicznego w wersji 4.0, i to on wyprowadzi poprawny ogólny typ argumentu, ale nie miałem jeszcze okazji go zweryfikować. Nie chodzi o to, że pod osłonami robi coś innego niż powyższy kod, ale może tak jest. –

5
this.GetType().GetMethod("DoSomething").MakeGenericMethod(p.Value.GetType()).Invoke(this, new object[]{p.Name, p.Value}); 

Powinien działać.

3

Typy ogólne nie mogą być określone w środowisku wykonawczym w sposób, w jaki chcesz tutaj.

Najprostszą opcją byłoby dodanie nietypowego przeciążenia DoSomething lub po prostu wywołanie DoSomething<object> i zignorowanie p.DisplayType. Chyba że SendToDatabase zależy od typu kompilacji z value (i prawdopodobnie nie powinien), nie powinno być nic złego w przyznawaniu go object.

Jeśli nie możesz tego zrobić, musisz zadzwonić pod numer DoSomething, korzystając z funkcji odbicia, a otrzymasz duży hit wydajności.

1

Ściśle mówiąc, możesz użyć do tego celu MethodInfo.MakeGenericMethod.

Ale polecam zmienić DoSomething na nietypową formę, ponieważ nie jest oczywiste, czy naprawdę powinno być ogólne.

+0

Po prostu uprościliśmy program do wyjaśnienia. To jest rzeczywiście najbardziej eleganckie rozwiązanie, uwierz w to lub nie. :) dzięki! – Sarit

3

Najpierw musimy konwertować p.Value do właściwego rodzaju, ponieważ nawet jeśli wiemy, typ w czasie kompilacji nie możemy przekazać ciąg prosto do sposobu ...

DoSomething<Int32>("10"); // Build error 

przypadku prostych typów liczbowych i DateTime, możemy użyć

object convertedValue = Convert.ChangeType(p.Value, p.DisplayType); 

teraz możemy użyć refleksji do wywołania metody rodzajowe wymagane ...

typeof(ClassExample) 
    .GetMethod("DoSomething") 
    .MakeGenericMethod(p.DisplayType) 
    .Invoke(this, new object[] { p.Name, convertedValue });