如何在C#中管理非托管DLL调用的多个版本的使用?
我不知道是否有人能给我指出正确的方向我对c#还相当陌生,所以对我宽容点 我的代码使用了一个非托管DLL,它是一个提供的API,用于与智能卡读卡器接口,我没有对DLL的控制权,我只是想用c#将其包装起来,使其更易于使用。到目前为止,我已经设法做到了这一点,但我发现现在需要测试这个DLL的多个版本,它的入口点相同,但参数可能不同 我尝试了一些类似的方法来组织我的包装器类如何在C#中管理非托管DLL调用的多个版本的使用?,c#,dll,unmanaged,dllimport,multiple-versions,C#,Dll,Unmanaged,Dllimport,Multiple Versions,我不知道是否有人能给我指出正确的方向我对c#还相当陌生,所以对我宽容点 我的代码使用了一个非托管DLL,它是一个提供的API,用于与智能卡读卡器接口,我没有对DLL的控制权,我只是想用c#将其包装起来,使其更易于使用。到目前为止,我已经设法做到了这一点,但我发现现在需要测试这个DLL的多个版本,它的入口点相同,但参数可能不同 我尝试了一些类似的方法来组织我的包装器类 internal static class UnSafeNativeMethods { internal static c
internal static class UnSafeNativeMethods
{
internal static class READER
{
internal static class SDK20
{
[DllImport(dllpath, EntryPoint = "CV_SetCommunicationType")]
internal static extern int CV_SetCommunicationType(byte type);
...
}
internal static class SDK21
{
[DllImport(dllpath, EntryPoint = "CV_SetCommunicationType")]
internal static extern int CV_SetCommunicationType(byte type);
...
}
}
}
但在检查要使用的调用时,它会产生非常难看的代码
ReaderSDK sdk = ReaderSDK.SDK20 //Could come from a argument passed in or set in an
//instantiated class
...
switch (sdk)
{
case ReaderSDK.SDK20:
UnSafeNativeMethods.READER.SDK20.CV_SetCommunicationType(0x0);
break;
case ReaderSDK.SDK21:
UnSafeNativeMethods.READER.SDK21.CV_SetCommunicationType(0x0);
break;
...
}
这对我来说似乎很混乱,不知道是否有人能给我指出正确的方向
编辑:在下面的评论中,我提出了一些示例代码,但仍然不确定我是否在正确的轨道上,因为我的开关仍然存在,但它现在是一个具体的Factory类的一部分
public enum ConnectionType
{
RS232 = 0x0,
USB = 0x1,
UDP = 0x2
}
interface INativeMethods
{
string Name();
void SetCommunicationType(ConnectionType type);
}
class SDK20 : INativeMethods
{
public string Name()
{
return "SDK Version 2.0";
}
// Thanks to @dzendras for this!!
public void SetCommunicationType(ConnectionType type)
{
int result = UnSafeNativeMethods.READER.SDK20.CV_SetCommunicationType((byte)type);
switch (result)
{
case 0:
return;
case 1:
throw new NotSupportedException("Communication type not supported");
case 2:
throw AnyOtherMeaningfulException("Its message");
}
}
}
class SDK21 : INativeMethods
{
public string Name()
{
return "SDK Version 2.1";
}
// Thanks to @dzendras for this!!
public void SetCommunicationType(ConnectionType type)
{
int result = UnSafeNativeMethods.READER.SDK21.CV_SetCommunicationType((byte)type);
switch (result)
{
case 0:
return;
case 1:
throw new NotSupportedException("Communication type not supported");
case 2:
throw AnyOtherMeaningfulException("Its message");
}
}
}
class NativeMethodsFactory
{
private static NativeMethodsFactory instance = new NativeMethodsFactory();
private NativeMethodsFactory()
{
}
public static NativeMethodsFactory Instance
{
get { return NativeMethodsFactory.instance; }
}
public INativeMethods Get(ReaderSDK version)
{
switch (version)
{
case ReaderSDK.SDK20:
return new SDK20();
case ReaderSDK.SDK21:
return new SDK21();
default:
return new SDK20();
}
}
}
我做得对吗
这就是我现在如何实现对SDK的调用
// sdk passed in as enum, NativeMethods stored as class member.
NativeMethods = NativeMethodsFactory.Instance.Get(sdk);
...
NativeMethods.SetCommunicationType(ConnectionType.USB);
使用模式策略
有关模式的一些链接:
在工厂模式的帮助下,如何使用战略模式进行最终决策的一些示例
INativeMethods nativeMethods = NativeMethodsFactory.Get(UnsafeSdkVersion.V1);
nativeMethods.CV_SetCommunicationType(aType);
优点:
我建议更改托管API。调用C代码(从DLL)不应该强迫您使用结构化范例。你的包装应该是完全客观的。例如:
internal static extern int CV_SetCommunicationType(byte aType);
public void SetCommunicationType(byte type)
{
int result = CV_SetCommunicationType(type);
switch (result)
{
case 0:
return;
case 1:
throw new NotSupportedException("Communication type not supported");
case 2:
throw AnyOtherMeaningfulException("Its message");
}
}
在我看来,每次API调用都必须使用switch语句是非常不整洁的,我的问题是如何整理我的代码,所以我存储了一个引用,比如说类类型,然后从那里调用非托管调用,但我不确定如何做到这一点。尝试使用singleton类,但问题太多。但我是说c#。在C#上实现模式策略。您将有两种策略-对于每个版本,您还可以避免不必要的切换。哪个版本的execute可以存储在app.configI在C#-中找到了一个关于抽象工厂模式实现的例子。你向我展示了部分谜题,看起来很有希望,但在你的例子中我似乎缺少关键步骤,我如何从NativeMethodFactory到SDK实例?NativeMethodsFactory是静态类吗?,当我遇到无法从静态类返回实例成员的问题时,我已经看到了变化。是的,这和我所说的变化非常相似。和Factory的主要区别在于,您将只在一个位置进行切换,而所有其他代码都将依赖于接口。并执行相同的方法,但根据需要使用不同的实现。NativeMethodsFactory可以是静态的,也可以不是静态的。根据您的意愿和需要实施工厂。工厂的主要目标是基于版本构造对象。只有工厂应该知道具体的实现,所有其他代码都应该使用工厂和接口。谢谢dzendras,这非常有帮助。我通常不使用匈牙利符号,但在本例中,我从未改变SDK示例附带的声明(有很多声明)。这如何帮助我包装多个版本的调用?我知道我遗漏了什么你能帮我把这些点连起来吗?你能在3号上展开吗。寻找类…将返回值设置为异常将是一项艰巨的工作,返回的值是一个字节,而且有很多,但我明白你的意思,谢谢。你可以随时对我的答案进行投票:)你提出的解决方案很好。但是,如果API发生更改(某些参数或新方法),您的代码将降级。。。没有更广泛的背景,我找不到任何解决方案。