2

我想知道是否有人能指出我正确的方向我对 c# 还很陌生,所以请放轻松。

我的代码使用非托管 DLL,它是提供的用于与智能卡读卡器接口的 API,我无法控制 DLL,我只想将其包装在 c# 中以使其更易于使用。到目前为止,我已经设法做到了这一点,但我现在发现需要测试这个 DLL 的多个版本,这些版本的入口点相同,但参数可能不同。

我尝试了一些类似的方法来组织我的包装类;

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

这对我来说似乎很乱,想知道是否有人能指出我正确的方向......


编辑:离开下面的评论,我想出了一些示例代码,仍然不确定我是否在正确的轨道上,因为我的开关仍然存在,但它现在是混凝土工厂类的一部分。

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

2 回答 2

2

使用模式策略

关于模式的一些链接:

http://www.oodesign.com/strategy-pattern.html

策略模式的真实示例

在工厂模式的帮助下,使用策略模式最终如何实现的一些示例。

INativeMethods nativeMethods = NativeMethodsFactory.Get(UnsafeSdkVersion.V1);
nativeMethods.CV_SetCommunicationType(aType);

好处:

  1. 通过接口和工厂解耦
  2. 没有开关
  3. 易于添加新版本,所有其他代码都独立于要使用的版本。
于 2012-06-19T17:57:20.467 回答
1

我建议更改您的托管 API。调用 C 代码(从 DLL)不应该强迫你使用结构范式。你的包装应该是完全客观的。例如:

internal static extern int CV_SetCommunicationType(byte aType);
  1. 如果成功,则返回的 int 为 0,我想任何其他指示错误的值。返回 void 并在内部将代码从 DLL 调用转换为异常。

    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");
         }
     }
    
  2. 为 aType 创建一个枚举。

  3. 求课。静态方法是纯粹的邪恶。分析您的领域并寻找对象和行为。例如,这可能是(愚蠢的名字,我知道...)ConnectionManager 的方法。

  4. 取决于合同。让您的类(针对不同的 SDK)实现一些通用接口。

  5. 不要以示例方法中显示的方式使用匈牙利符号。

于 2012-06-20T06:14:40.670 回答