没有接口的密封类的复合模式



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

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

根据你显示的代码示例,答案是你不能。您需要能够通过设置属性或创建具有不同构造函数参数的新实例来修改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.
}
}

编译器错误消息

无法将类型"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;
}
}

所以现在你的"包装器"根据需要公开了第三方依赖项

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

或直接

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

引用用户定义的转换运算符(C# 参考(

可以允许抽象您的代码

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

最新更新