只是一些考虑因素:
替代方案#one
编辑:这种方法需要更改编译方法,这很困难,并且需要注入、程序集修改或 AOP 领域常用的其他方法。考虑下面的方法二,这是更容易的。
- 删除所有具有相同签名的函数,保留每个函数一个
- Use
GetIlAsByteArray
创建您的动态方法DllImport
method
- Use 这里描述的技术要操作函数的 IL,您可以在此处更改 DllImport 属性等。
- 创建这些函数的委托并缓存您的调用
- 返回委托
替代方案#二:
编辑:这种替代方法一开始似乎有点复杂,但有人已经为你完成了这项工作。抬头这篇优秀的 CodeProject 文章只需下载并使用其代码即可动态创建 DllImport 风格的方法。基本上,它可以归结为:
- 删除所有 DllImport
- 创建您自己的 DllImport 包装器:采用 dll 名称和函数名称(假设所有签名都相同)
- 包装器执行“手动”DllImportLoadLibrary or LoadLibraryEx使用 dllimport API 函数
- 包装器为您创建一个方法
MethodBuilder
.
- 返回该方法的委托,您可以将其用作函数。
替代方案#三
编辑:进一步看,有一个更简单的方法:只需使用DefinePInvokeMethod这满足了你所需要的一切。 MSDN 链接已经给出了一个很好的示例,但提供了一个完整的包装器,可以根据 DLL 和函数名称创建任何本机 DLL这篇 CodeProject 文章.
- 删除所有 DllImport 样式签名
- 创建一个简单的包装方法
DefinePInvokeMethod
- 确保添加简单的缓存(字典?)以防止在每次调用时构建整个方法
- 从包装器返回一个委托。
下面是这种方法在代码中的样子,您可以根据需要重用返回的委托,每个方法只应完成一次昂贵的动态方法构建。
编辑:更新了代码示例以与任何委托一起使用,并自动反映委托签名中的正确返回类型和参数类型。通过这种方式,我们将实现与签名完全解耦,考虑到您当前的情况,这是我们能做的最好的事情。优点:具有类型安全性和单点更改,这意味着:非常容易管理。
// expand this list to contain all your variants
// this is basically all you need to adjust (!!!)
public delegate int Function01(byte[] b);
public delegate int Function02();
public delegate void Function03();
public delegate double Function04(int p, byte b, short s);
// TODO: add some typical error handling
public T CreateDynamicDllInvoke<T>(string functionName, string library)
{
// create in-memory assembly, module and type
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName("DynamicDllInvoke"),
AssemblyBuilderAccess.Run);
ModuleBuilder modBuilder = assemblyBuilder.DefineDynamicModule("DynamicDllModule");
// note: without TypeBuilder, you can create global functions
// on the module level, but you cannot create delegates to them
TypeBuilder typeBuilder = modBuilder.DefineType(
"DynamicDllInvokeType",
TypeAttributes.Public | TypeAttributes.UnicodeClass);
// get params from delegate dynamically (!), trick from Eric Lippert
MethodInfo delegateMI = typeof(T).GetMethod("Invoke");
Type[] delegateParams = (from param in delegateMI.GetParameters()
select param.ParameterType).ToArray();
// automatically create the correct signagure for PInvoke
MethodBuilder methodBuilder = typeBuilder.DefinePInvokeMethod(
functionName,
library,
MethodAttributes.Public |
MethodAttributes.Static |
MethodAttributes.PinvokeImpl,
CallingConventions.Standard,
delegateMI.ReturnType, /* the return type */
delegateParams, /* array of parameters from delegate T */
CallingConvention.Winapi,
CharSet.Ansi);
// needed according to MSDN
methodBuilder.SetImplementationFlags(
methodBuilder.GetMethodImplementationFlags() |
MethodImplAttributes.PreserveSig);
Type dynamicType = typeBuilder.CreateType();
MethodInfo methodInfo = dynamicType.GetMethod(functionName);
// create the delegate of type T, double casting is necessary
return (T) (object) Delegate.CreateDelegate(
typeof(T),
methodInfo, true);
}
// call it as follows, simply use the appropriate delegate and the
// the rest "just works":
Function02 getTickCount = CreateDynamicDllInvoke<Function02>
("GetTickCount", "kernel32.dll");
Debug.WriteLine(getTickCount());
我想其他方法也是可能的(就像本线程中其他人提到的模板方法)。
Update:添加了一个链接优秀的代码项目文章.
Update:添加了第三种更简单的方法。
Update:添加了代码示例
Update:更新的代码示例可与任何函数原型无缝协作
Update:修复了可怕的错误:typeof(Function02)
应该typeof(T)
当然