Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
有没有合适的设计模式来重构这个C#代码_C#_.net_Generics_Design Patterns_Refactoring - Fatal编程技术网

有没有合适的设计模式来重构这个C#代码

有没有合适的设计模式来重构这个C#代码,c#,.net,generics,design-patterns,refactoring,C#,.net,Generics,Design Patterns,Refactoring,我有两个不同的第三方程序集,它们为业务服务提供相同的API,使用相同的类名(~40个类/类型/扩展),但位于不同的程序集中: Company.Assemply.V1 Company.Assemply.V2 我引用项目中的两个程序集 这些程序集没有通用接口,第三方也无法提供通用接口 因此,c#编译器将两个程序集中的每个类型视为不同的类型 我想为每个程序集实现一个类Myservice,以支持V1/V2两个版本 我使用以下代码来实现Myservice.V1.Myclass /

我有两个不同的第三方程序集,它们为业务服务提供相同的API,使用相同的类名(~40个类/类型/扩展),但位于不同的程序集中:

    Company.Assemply.V1
    Company.Assemply.V2
我引用项目中的两个程序集

这些程序集没有通用接口,第三方也无法提供通用接口

因此,c#编译器将两个程序集中的每个类型视为不同的类型

我想为每个程序集实现一个类
Myservice
,以支持V1/V2两个版本

我使用以下代码来实现
Myservice.V1.Myclass

    //#define V1

    #if V1
       using  Company.Assemply.V1;
    #else
       using  Company.Assemply.V2;
    #endif

    #if V1
      namespace Myservice.V1
    #else
      namespace Myservice.V2
    #endif
    {
       //my implementation that use all classes /types in any v1/v2 assembly
        class MyClass {.... }
     }
然后,我将相同的代码复制并粘贴到其他c#文件
MyClassV2.cs
(大约400行)中,以获得
Myservice.V2.Myclass
,并取消对编译器标志
#define V1

我不能用泛型

        MyClass  <T> where T:??
MyClass,其中T:??
因为T没有公共接口

这两个班工作得很好

问题是在维护v1时,我必须将代码复制/粘贴到另一个文件
MyClassV2.cs
中,并取消对编译器标志
#define v1
的注释以支持V2

有没有更好的方法/合适的设计模式/重构技术可以解决这样的问题。 我想使用/维护一个代码库,避免复制/粘贴另一个类版本

请给我一个重构上述代码的示例。

一个选项是使用,这是向BCL和不使用它们的第三方代码添加抽象的常用方法。例如,您在第三方程序集中有一个名为
MyClass
的类型,并且
V1
V2
共享相同的成员:

public interface IMyClass
{
    // All members of MyClass 
    // (except we have a special case for DoSomething() because it
    // has a return type SomeType we also need to adapt to ISomeType).

    ISomeType DoSomething();
}

public class MyClassV1 : V1.MyClass, IMyClass
{
    // No need to re-implement members (base class satisfies interface)
    // However, if there are return parameters, you will need to 
    // also use a decorator pattern to wrap them in another adapter.

    public override ISomeType DoSomething()
    {
        return new SomeTypeV1(base.DoSomething());
    }

}

public class MyClassV2 : V2.MyClass, IMyClass
{
}

public interface ISomeType
{
     // All members of SomeType
}

public class SomeTypeV1 : ISomeType
{
    private readonly SomeType someType;

    public SomeType(SomeType someType)
    {
        this.someType = someType;
    }

    // re-implement all members and cascade the call to someType
}
然后您可以在应用程序中使用
IMyClass
,使用DI注入您需要的任何一个

public class HomeController : Controller
{
    private readonly IMyClass myClass;

    public HomeController(IMyClass myClass)
    {
        this.myClass = myClass
    }
}

如果您需要在运行时在实现之间切换,请考虑../P>< P>选项之一是使用它,这是向BCL和不使用它们的第三方代码添加抽象的常用方法。例如,您在第三方程序集中有一个名为

MyClass
的类型,并且
V1
V2
共享相同的成员:

public interface IMyClass
{
    // All members of MyClass 
    // (except we have a special case for DoSomething() because it
    // has a return type SomeType we also need to adapt to ISomeType).

    ISomeType DoSomething();
}

public class MyClassV1 : V1.MyClass, IMyClass
{
    // No need to re-implement members (base class satisfies interface)
    // However, if there are return parameters, you will need to 
    // also use a decorator pattern to wrap them in another adapter.

    public override ISomeType DoSomething()
    {
        return new SomeTypeV1(base.DoSomething());
    }

}

public class MyClassV2 : V2.MyClass, IMyClass
{
}

public interface ISomeType
{
     // All members of SomeType
}

public class SomeTypeV1 : ISomeType
{
    private readonly SomeType someType;

    public SomeType(SomeType someType)
    {
        this.someType = someType;
    }

    // re-implement all members and cascade the call to someType
}
然后您可以在应用程序中使用
IMyClass
,使用DI注入您需要的任何一个

public class HomeController : Controller
{
    private readonly IMyClass myClass;

    public HomeController(IMyClass myClass)
    {
        this.myClass = myClass
    }
}

如果您需要在运行时在实现之间切换,请考虑.< /p>如何通过在运行时解析动态特性的相应程序集?将它们封装在自己的类中。然后您可以自由地决定继承的外观。当你使用MVVM模式时,你必须做很多这样的包装。@Christopher,你能给我一个两个程序集的例子吗?当你使用MVVM模式时,你需要对每个ViewModel类的所有属性进行更改通知。95%的模型类没有更改通知。或者甚至是可以覆盖的属性(大多数都有字段)。解决方案:编写自己的类。它们的唯一目的是将模型类保存在私有变量中。它们的所有属性都只围绕对字段的调用进行包装。它们的所有函数都围绕着模型函数。最终结果:模型类可以保持对realiy的遗忘。您可以获得所需的确切项目和类。如何在运行时传递解析动态的相应程序集?将它们包装在您自己的类中。然后您可以自由地决定继承的外观。当你使用MVVM模式时,你必须做很多这样的包装。@Christopher,你能给我一个两个程序集的例子吗?当你使用MVVM模式时,你需要对每个ViewModel类的所有属性进行更改通知。95%的模型类没有更改通知。或者甚至是可以覆盖的属性(大多数都有字段)。解决方案:编写自己的类。它们的唯一目的是将模型类保存在私有变量中。它们的所有属性都只围绕对字段的调用进行包装。它们的所有函数都围绕着模型函数。最终结果:模型类可以保持对realiy的遗忘。您可以获得所需的确切proe属性和类。类中的某些方法返回/具有位于程序集中的数据类型参数。我必须为这些类型构建单独的适配器吗?在这种情况下,您需要一个装饰器模式来包装API返回的实例。请参阅我的最新答案。根据API公开的库中的其他类型的数量,可能还有其他特殊情况需要在装饰器中包装。类中的某些方法返回/具有位于程序集中的数据类型参数。我必须为这些类型构建单独的适配器吗?在这种情况下,您需要一个装饰器模式来包装API返回的实例。请参阅我的最新答案。根据API公开的库中的其他类型的数量,可能还有其他特殊情况需要在装饰器中包装。