2012-06-22 15 views
5

Wszystko, mam metodę, która jest obecnie używana do wywoływania bibliotek DLL typu zwracającego bool, działa to świetnie. Metoda ta jestDefiniowanie metod ogólnych

public static bool InvokeDLL(string strDllName, string strNameSpace, 
          string strClassName, string strMethodName, 
          ref object[] parameters, 
          ref string strInformation, 
          bool bWarnings = false) 
{ 
    try 
    { 
     // Check if user has access to requested .dll. 
     if (!File.Exists(Path.GetFullPath(strDllName))) 
     { 
      strInformation = String.Format("Cannot locate file '{0}'!", 
              Path.GetFullPath(strDllName)); 
      return false; 
     } 
     else 
     { 
      // Execute the method from the requested .dll using reflection. 
      Assembly DLL = Assembly.LoadFrom(Path.GetFullPath(strDllName)); 
      Type classType = DLL.GetType(String.Format("{0}.{1}", 
             strNameSpace, strClassName)); 
      if (classType != null) 
      { 
       object classInstance = Activator.CreateInstance(classType); 
       MethodInfo methodInfo = classType.GetMethod(strMethodName); 
       if (methodInfo != null) 
       { 
        object result = null; 
        result = methodInfo.Invoke(classInstance, new object[] { parameters }); 
        return Convert.ToBoolean(result); 
       } 
      } 

      // Invocation failed fatally. 
      strInformation = String.Format("Could not invoke the requested DLL '{0}'! " + 
              "Please insure that you have specified the namespace, class name " + 
              "method and respective parameters correctly!", 
              Path.GetFullPath(strDllName)); 
      return false; 

     } 
    } 
    catch (Exception eX) 
    { 
     strInformation = String.Format("DLL Error: {0}!", eX.Message); 
     if (bWarnings) 
      Utils.ErrMsg(eX.Message); 
     return false; 
    } 
} 

Teraz chcę przedłużyć ten sposób, aby można było pobierać wartości zwracanych z DLL z dowolnego typu. Planowałem zrobić to za pomocą leków generycznych, ale natychmiast udałem się na nieznane mi terytorium. Jak zwrócić T, gdy jest nieznany w czasie kompilacji, spojrzałem na refleksję, ale nie jestem pewien, w jaki sposób byłby używany w tym przypadku. Zapoznaj się z pierwszym sprawdzeniem w powyższym kodzie:

public static T InvokeDLL<T>(string strDllName, string strNameSpace, 
          string strClassName, string strMethodName, 
          ref object[] parameters, ref string strInformation, 
          bool bWarnings = false) 
{ 
    try 
    { 
     // Check if user has access to requested .dll. 
     if (!File.Exists(Path.GetFullPath(strDllName))) 
     { 
      strInformation = String.Format("Cannot locate file '{0}'!", 
              Path.GetFullPath(strDllName)); 
      return "WHAT/HOW??"; 
     ... 

Jak mogę osiągnąć to, co chcę, czy powinienem po prostu przeciążać metodę?

Dziękuję bardzo za pomoc.

+3

W drugim bloku kodu, który wygląda jak warunek błędu. Czy nie byłoby lepiej "rzucić nowe ArgumentException()"? Jeśli chodzi o inne zwroty, rób to, co sugeruje Heinzi. –

+0

+1 Nie jestem pewien w tym przypadku. Czasami lepiej jest zdefiniować przyczynę błędu jako wyjątek. Wiadomość może czasami być tajemnicza dla użytkownika. Jednak powiedziawszy, że nie jestem pewien, jest to jeden z tych przypadków. Dziękuję za poświęcony czas ... – MoonKnight

+2

Zgadzam się z Jessem - jeśli nie uda ci się znaleźć lub wywołać metody, powinieneś rzucić. Użytkownik powinien oczekiwać, że powrót oznacza sukces. Zarządzany świat używa wyjątku do komunikowania takich awarii. Nie specjalistyczne zwroty. – payo

Odpowiedz

6

wymienić

return false; 

przez

return default(T); 

i

return Convert.ToBoolean(result); 

przez

return (T)result; 
+0

To wielkie dzięki. Czy wiesz, gdzie mogę dowiedzieć się, jakie są wartości domyślne każdego typu - nie wydaje się, że jest w MSDN lub w przewodniku po języku? – MoonKnight

+1

@Killercam [tutaj] (http://msdn.microsoft.com/en-us/library/83fhsxwc (v = vs.100) .aspx), typy referencji zawsze mają wartość 'null'. –

+0

@AdamHouldsworth bardzo za to dziękuję. Najbardziej ceniony ... – MoonKnight

4

When nie masz prawdziwej wartości z biblioteki DLL, oczywiście musisz stworzyć wartość skądś. Jedynym sposobem, który działa dla każdego możliwego typu, jest , który daje dowolną wartość domyślną dla tego typu (tj. 0 dla każdego rodzaju odniesienia).

Jeśli umieścisz wiązania typu na parametrze type, możesz uzyskać więcej opcji, ale kosztem generyczności.

2

chciałbym zrobić coś takiego:

public static InvokeDLLResult<T> InvokeDLL<T>(string strDllName, string strNameSpace, 
         string strClassName, string strMethodName, 
         ref object[] parameters, 
         ref string strInformation, 
         bool bWarnings = false) 
    { 
     try 
     { 
      // Check if user has access to requested .dll. 
      if (!File.Exists(Path.GetFullPath(strDllName))) 
      { 
       strInformation = String.Format("Cannot locate file '{0}'!", 
                 Path.GetFullPath(strDllName)); 
       return InvokeDLLResult<T>.Failure; 
      } 
      else 
      { 
       // Execute the method from the requested .dll using reflection. 
       Assembly DLL = Assembly.LoadFrom(Path.GetFullPath(strDllName)); 
       Type classType = DLL.GetType(String.Format("{0}.{1}", strNameSpace, strClassName)); 
       if (classType != null) 
       { 
        object classInstance = Activator.CreateInstance(classType); 
        MethodInfo methodInfo = classType.GetMethod(strMethodName); 
        if (methodInfo != null) 
        { 
         object result = null; 
         result = methodInfo.Invoke(classInstance, new object[] { parameters }); 
         return new InvokeDLLResult<T>(true, (T) Convert.ChangeType(result, methodInfo.ReturnType)); 
        } 
       } 

       // Invocation failed fatally. 
       strInformation = String.Format("Could not invoke the requested DLL '{0}'! " + 
                 "Please insure that you have specified the namespace, class name " + 
                 "method and respective parameters correctly!", 
                 Path.GetFullPath(strDllName)); 
       return InvokeDLLResult<T>.Failure; 

      } 
     } 
     catch (Exception eX) 
     { 
      strInformation = String.Format("DLL Error: {0}!", eX.Message); 
      if (bWarnings) 
       Debug.WriteLine(eX.Message); 
      return InvokeDLLResult<T>.Failure; 
     } 
    } 

    public class InvokeDLLResult<T> 
    { 
     public InvokeDLLResult(bool success, T result) 
     { 
      Success = success; 
      Result = result; 
     } 

     public bool Success { get; private set; } 
     public T Result { get; private set; } 

     public static InvokeDLLResult<T> Failure = new InvokeDLLResult<T>(false, default(T)); 
    } 

Albo, chciałbym napisać metodę TryInvokeDLL, wykorzystując parametr wyjściowy, aby powrócić wynik.

+0

Podoba mi się to. Pozdrawiam ... – MoonKnight

+0

+1, bardzo elegancki. Myślę, że możesz pominąć 'Convert.ChangeType (result, methodInfo.ReturnType)'. Ponieważ 'result' został zwrócony przez metodę wymienioną przez' methodInfo', musi on już mieć typ dynamiczny 'methodInfo.ReturnType'. Aha, i dodałbym "strInformation" do zwracanego obiektu: parametry "ref" są brzydkie. ;-) – Heinzi

+0

Masz rację w obu sprawach, @Heinzi. – neontapir

Powiązane problemy