猿问

无接口的密封类的复合模式

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


tl;dr:如何将密封类重新实现为接口?


代码示例:


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)}");

    }

}


慕斯709654
浏览 120回答 2
2回答

当年话下

根据您显示的代码示例,答案是您不能。您需要能够IDontHaveControlOverThis.ArgumentClass通过设置属性或创建具有不同构造函数参数的新实例来修改 的行为,以便修改服务调用。(现在它总是返回相同的字符串,因此服务调用始终相同)如果您能够通过设置属性来修改 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.    }}

30秒到达战场

编译器错误信息无法将类型“MyCode.MyArgumentClass”隐式转换为“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;    }}所以现在你的“包装器”根据需要公开了第 3 方依赖项 IDontHaveControlOverThis.ArgumentClass myArg = new MyCode.MyArgumentClass();或直接var myArg = new MyCode.MyArgumentClass();Console.WriteLine($"Result: {service.ServiceCall(myArg)}");这可以允许抽象你的代码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);        }    }}
随时随地看视频慕课网APP
我要回答