没有接口的 sealed class 的复合模式

Composite pattern of sealed class that has no interface

假设我正在使用一个我无法控制 的库。该库公开了需要某些 class 参数的服务。 Class 标记为密封并且没有接口

tl;dr:如何将 sealed class 重新实现为 interface?

代码示例:

using System;

namespace IDontHaveControlOverThis
{
    // Note no interface and the class is being sealed
    public sealed class ArgumentClass
    {
        public String AnyCall() => "ArgumentClass::AnyCall";
    }

    public sealed class ServiceClass
    {
        public String ServiceCall(ArgumentClass argument) => $"ServiceClass::ServiceCall({argument.AnyCall()})";
    }
}

namespace MyCode
{
    // Composite pattern, basically I need: "is a ArgumentClass"
    // Obviously doesn't work - can't extend from sealed class
    public class MyArgumentClass : IDontHaveControlOverThis.ArgumentClass
    {
        private IDontHaveControlOverThis.ArgumentClass arg = new IDontHaveControlOverThis.ArgumentClass();

        public String AnyCall() => $"MyArgumentCLass::AnyCall({arg.AnyCall()})";
    }
}

public class Program
{
    public static void Main()
    {
        // I don't have control over this
        IDontHaveControlOverThis.ServiceClass service = new IDontHaveControlOverThis.ServiceClass();


        //This obviously works
        IDontHaveControlOverThis.ArgumentClass arg = new IDontHaveControlOverThis.ArgumentClass();
        Console.WriteLine($"Result: {service.ServiceCall(arg)}");

        // How to make this work?
        IDontHaveControlOverThis.ArgumentClass myArg = new MyCode.MyArgumentClass();
        Console.WriteLine($"Result: {service.ServiceCall(myArg)}");
    }
}

编译器错误信息

Cannot implicitly convert type 'MyCode.MyArgumentClass' to 'IDontHaveControlOverThis.ArgumentClass'

注:强调我的

应该会提示您可以做什么

public class MyArgumentClass {
    private IDontHaveControlOverThis.ArgumentClass arg = new IDontHaveControlOverThis.ArgumentClass();

    public String AnyCall() => $"MyArgumentCLass::AnyCall({arg.AnyCall()})";


    public static implicit operator IDontHaveControlOverThis.ArgumentClass(MyArgumentClass source) {

        return source.arg;
    }
}

现在您的 "wrapper" 根据需要公开了第三方依赖项

 IDontHaveControlOverThis.ArgumentClass myArg = new MyCode.MyArgumentClass();

或直接

var myArg = new MyCode.MyArgumentClass();
Console.WriteLine($"Result: {service.ServiceCall(myArg)}");

参考User-defined conversion operators (C# reference)

这可以允许抽象您的代码

namespace MyCode {

    public interface IMyService {
        String ServiceCall(MyArgumentClass argument);
    }

    public class MyServiceClass : IMyService {
        public string ServiceCall(MyArgumentClass argument) {
            IDontHaveControlOverThis.ServiceClass service = new IDontHaveControlOverThis.ServiceClass();
            return service.ServiceCall(argument);
        }
    }
}

根据您显示的代码示例,答案是您不能。您需要能够通过设置 属性 或创建具有不同构造函数参数的新实例来修改 IDontHaveControlOverThis.ArgumentClass 的行为,以便修改服务调用。 (现在总是 returns 相同的字符串,所以服务调用总是相同的)

如果您能够通过设置属性来修改 ArgumentClass 的行为。 您可以在自己的代码中为密封的 类 创建包装器,并在整个代码库中使用它。

public class MyArgumentClass
{
        // TODO: Set this to a useful value of ArgumentClass.
    internal IDontHaveControlOverThis.ArgumentClass InnerArgumentClass { get; }
    public virtual string AnyCall() => "???";
}

public class MyServiceClass
{
    private IDontHaveControlOverThis.ServiceClass innerServiceClass
            = new IDontHaveControlOverThis.ServiceClass();

    public virtual string ServiceCall(MyArgumentClass argument)
    {
        return innerServiceClass.ServiceCall(argument.InnerArgumentClass);
    }
}

public class MyArgumentClass
{
    public virtual string AnyCall() => "???";
}

public class MyServiceClass
{
    private IDontHaveControlOverThis.ServiceClass innerServiceClass
            = new IDontHaveControlOverThis.ServiceClass();

    public string ServiceCall(MyArgumentClass argument)
    {
        var serviceArgument = Convert(argument);
        return innerServiceClass.ServiceCall(serviceArgument);
    }

    private IDontHaveControlOverThis.ArgumentClass Convert(MyArgumentClass argument)
    {
        // TODO: implement.
    }
}