2012-06-22 3 views
5

У меня есть метод, который в настоящее время используется для вызова DLL-типа возвращаемого типа bool, это отлично работает. Этот методОпределение общих методов

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

Теперь я хочу, чтобы распространить этот метод, чтобы я мог получить возвращаемые значения из DLL из любого типа. Я планировал сделать это с помощью дженериков, но сразу ушел на неизвестную мне территорию. Как вернуть T, когда он неизвестен во время компиляции, я посмотрел на размышления, но я не уверен, как он будет использоваться в этом случае. Возьмите первый чек в коде выше

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??"; 
     ... 

Как я могу добиться того, чего я хочу, или я просто перегрузить метод?

Большое спасибо за помощь.

+3

В вашем втором блоке кода это выглядит как условие ошибки. Не было бы более уместным «бросать новое ArgumentException()»? Что касается других возвратов, сделайте то, что предлагает Хайнци. –

+0

+1 Я не уверен в этом случае. Иногда яснее определить причину ошибки самостоятельно как Exception.Message иногда может быть загадочным для пользователя. Однако, сказав, что я не уверен, что это один из таких случаев. Спасибо за ваше время ... – MoonKnight

+2

Я согласен с Джесси - если вам не удается найти или вызвать метод, вы должны бросить. Пользователь должен ожидать, что возвращение подразумевает успех. Управляемый мир использует исключение для сообщения об ошибках, подобных этому. Неспециализированные возвращения. – payo

ответ

6

Заменить

return false; 

от

return default(T); 

и

return Convert.ToBoolean(result); 

от

return (T)result; 
+0

Большое спасибо. Знаете ли вы, где я могу узнать, каковы значения по умолчанию для каждого типа - похоже, это не MSDN или в руководстве по языку? – MoonKnight

+1

@Killercam [Здесь] (http://msdn.microsoft.com/en-us/library/83fhsxwc (v = vs.100) .aspx), ссылочные типы всегда «null». –

+0

@AdamHouldsworth благодарит за это. Самое ценное ... – MoonKnight

4

When у вас нет реальной ценности из DLL, вам, очевидно, нужно что-то создать. Единственный способ, который работает для любого возможного типа T, - return default(T), который дает значение по умолчанию для этого типа (т. Е. 0 для int, null для любого ссылочного типа).

Если вы поместите ограничения типа на параметр типа, вы можете получить больше опций, но за счет типичности.

2

Я хотел бы сделать что-то вроде этого:

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

Или, я бы написать метод TryInvokeDLL, используя выходной параметр для возврата результата.

+0

Мне это нравится. Cheers ... – MoonKnight

+0

+1, очень элегантный. Я думаю, вы можете пропустить 'Convert.ChangeType (result, methodInfo.ReturnType)', хотя. Поскольку 'result' был возвращен методом, на который ссылается' methodInfo', он должен иметь динамический тип 'methodInfo.ReturnType'. О, и я бы добавил 'strInformation' к возвращаемому объекту: параметры' ref' являются уродливыми. ;-) – Heinzi

+0

Вы правы по обоим пунктам, @Heinzi. – neontapir

Смежные вопросы