MoonKnight
MoonKnight

Reputation: 23831

Defining Generic Methods

All, I have a method that is currently used to invoke DLLs of return type bool, this works great. This method is

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

Now, I want to extend this method so that I can retrieve return values from a DLL of any type. I planned to do this using generics but immediately have gone into territory unknown to me. How do I return T when it is unknown at compile time, I have looked at reflection but I am unsure how it would be used in this case. Take the first check in the above code

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

How can I achieve what I want, or shall I just overload the method?

Thanks very much for your help.

Upvotes: 5

Views: 494

Answers (3)

neontapir
neontapir

Reputation: 4736

I would do something like this:

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

Or, I would write a TryInvokeDLL method, using an out parameter to return the result.

Upvotes: 2

Matthew Walton
Matthew Walton

Reputation: 9969

When you've not got a real value from the DLL, you obviously have to create a value from somewhere. The only way that works for every possible type T is return default(T) which gives whatever the default value for that type is (i.e. 0 for int, null for any reference type).

If you place type constraints on the type parameter you can get more options, but at the expense of genericity.

Upvotes: 4

Heinzi
Heinzi

Reputation: 172468

Replace

return false;

by

return default(T);

and

return Convert.ToBoolean(result);

by

return (T)result;

Upvotes: 6

Related Questions