C# 如何避免强制转换到特定接口 背景信息

C# 如何避免强制转换到特定接口 背景信息,c#,interface,solid-principles,C#,Interface,Solid Principles,我有一组接口/类,如下所示。为了简单起见,想象更多的属性、集合等 接口IMaster { //一些性质 } 接口IB:IMaster { 字符串PropOnA{get;set} } 接口IC:IMaster { 字符串PropOnB{get;set} } B类:IB C类:集成电路 ... 这些合同旨在存储数据(在每种情况下,数据的格式略有不同)。有很多代码使用这些契约来获取数据、格式化数据、处理数据、编写数据等等。 我们开发了一个完整的库,通过反转控制,它看不到任何这些契约的具体实现(B,C

我有一组接口/类,如下所示。为了简单起见,想象更多的属性、集合等

接口IMaster
{
//一些性质
}
接口IB:IMaster
{
字符串PropOnA{get;set}
}
接口IC:IMaster
{
字符串PropOnB{get;set}
}
B类:IB
C类:集成电路
...
这些合同旨在存储数据(在每种情况下,数据的格式略有不同)。有很多代码使用这些契约来获取数据、格式化数据、处理数据、编写数据等等。 我们开发了一个完整的库,通过反转控制,它看不到任何这些契约的具体实现(B,C),并允许用户对每个契约使用我们的“默认实现”,或者只加载他们自己的契约。我们有一个注册表,用户可以在其中注册不同的实现

为此,我实现了一种策略模式,其中基于当前任务的每种合同类型都有一种策略。为了简单起见,假设任务是写,实际上要复杂得多

interface IWriteStrategy
{
    public Write(IMaster thing);
}

class WriterA : IWriteStrategy

class WriterB : IWriteStrategy

etc
上述具体策略在我们的库中也从未“见过”,客户机必须注册自己的实现或我们的默认版本

设计缺陷?? 我不喜欢现在需要的每一个策略中的演员

public classWriterA : IWriteStrategy
{
    public void Write(IMaster thing)
    {
        if(thing is IA thingA)
        //do some work
    }
}

public classWriterB : IWriteStrategy
{
    public void Write(IMaster thing)
    {
        if(thing is IB thingB)
        //do some work
    }
}
我们要做的是能够在
IMaster
对象列表中循环并运行一些操作

foreach(var thing in Things)
{
    var strategy = GetStrategy(thing.GetType());  //this gets the strategy object from our `registry` if one exists
    strategy.Execute(thing);
}
上面的设计允许这一点,但似乎有一个缺陷,我不能为我的生活找到解决办法。我们必须转换到每个战略实施中的特定接口

我试过使用泛型,但似乎无法解决它

问题: 有什么更好的设计方法可以避免演员阵容,但仍然能够循环浏览
IMaster
事物列表,并对它们一视同仁?还是说演员阵容是绝对必要的

我试图遵循一个可靠的设计,但觉得演员阵容正在搞乱这一点,因为实施策略的客户将不得不进行演员阵容,以便在
Write
方法中实现任何功能

[编辑]
我已经更新了实现
IWriteStrategy

的类,也许使用Strategy模式并给出一个实现并执行它是合适的。让我举个例子

interface IMaster
{
    void ExecuteMaster();
}


class MasterOne : IMaster
{
    public void ExecuteMaster()
    {
        Console.WriteLine("Master One");
    }
}


class MasterTwo : IMaster
{
    public void ExecuteMaster()
    {
        Console.WriteLine("Master Two");
    }
}

和要执行的代码:

static void Main(string[] args)
{
    List<IWriteStrategy> writeStrategies = new List<IWriteStrategy>()
    {
        new WriterA(),
        new WriterB()
    };
    List<IMaster> executes = new List<IMaster>()
    {
         new MasterOne(),
         new MasterTwo()
    };

    for (int i = 0; i < writeStrategies.Count(); i++)
    {
         writeStrategies[i].Write(executes[i]);
    }
}
static void Main(字符串[]args)
{
List writeStrategies=新列表()
{
新WriterA(),
新WriterB()
};
列表执行=新列表()
{
新MasterOne(),
新Master2()
};
对于(int i=0;i
关于这一点,您将在一个策略工厂方法中进行所有强制转换:

 public interface IWriterStrategy
{
    void Execute();
}

public class WriterA : IWriterStrategy
{
    private readonly IA _thing;

    public WriterA(IA thing)
    {
        _thing = thing;
    }
    public void Execute()
    {
        Console.WriteLine(_thing.PropOnA);
    }
}

public class WriterB : IWriterStrategy
{
    private readonly IB _thing;
    public WriterB(IB thing)
    {
        _thing = thing;
    }
    public void Execute()
    {
        Console.WriteLine(_thing.PropOnB);
    }
}



public static class WriterFactory
{
    public static List<(Type Master, Type Writer)> RegisteredWriters = new List<(Type Master, Type Writer)>
        {
           (typeof(IA),  typeof(WriterA)),
           (typeof(IB),  typeof(WriterB))
        };
    public static IWriterStrategy GetStrategy(IMaster thing)
    {
        (Type Master, Type Writer) writerTypeItem = RegisteredWriters.Find(x => x.Master.IsAssignableFrom(thing.GetType()));
        if (writerTypeItem.Master != null)
        {
            return (IWriterStrategy)Activator.CreateInstance(writerTypeItem.Writer, thing);
        }
        throw new Exception("Strategy not found!");
    }
}

public interface IMaster
{
    //Some properties
}

public interface IA : IMaster
{
    string PropOnA { get; set; }
}

public interface IB : IMaster
{
    string PropOnB { get; set; }
}

public interface IC : IMaster
{
    string PropOnC { get; set; }
}

public class ThingB : IB
{
    public string PropOnB { get => "IB"; set => throw new NotImplementedException(); }
}

public class ThingA : IA
{
    public string PropOnA { get => "IA"; set => throw new NotImplementedException(); }
}

public class ThingC : IC
{
    public string PropOnC { get => "IC"; set => throw new NotImplementedException(); }
}

internal static class Program
{
    private static void Main(string[] args)
    {
        var things = new List<IMaster> { 
            new ThingA(),
            new ThingB()//,
            //new ThingC()
        };



        foreach (var thing in things)
        { 
            var strategy = WriterFactory.GetStrategy(thing);  //this gets the strategy object from our `registry` if one exists
            strategy.Execute();
        }
    }
}
公共接口IWriterStrategy
{
void Execute();
}
公共类编写:IWriterStrategy
{
私人只读信息系统;
公开写作(IA事务)
{
_事物=事物;
}
public void Execute()
{
控制台写入线(_thing.PropOnA);
}
}
公共类编写器B:IWriterStrategy
{
私有只读IB_东西;
公共作家B(IB事务)
{
_事物=事物;
}
public void Execute()
{
控制台写入线(_thing.PropOnB);
}
}
公共静态类WriterFactory
{
公共静态列表RegisteredWriters=新列表
{
(IA),(WriterA),,
(类型(IB),类型(WriterB))
};
公共静态IWriterStrategy GetStrategy(IMaster thing)
{
(Type Master,Type Writer)writerTypeItem=RegisteredWriters.Find(x=>x.Master.IsAssignableFrom(thing.GetType());
if(writerTypeItem.Master!=null)
{
return(IWriterStrategy)Activator.CreateInstance(writerTypeItem.Writer,thing);
}
抛出新异常(“未找到策略!”);
}
}
公共接口IMaster
{
//一些性质
}
公共接口IA:IMaster
{
字符串PropOnA{get;set;}
}
公共接口IB:IMaster
{
字符串PropOnB{get;set;}
}
公共接口IC:IMaster
{
字符串PropOnC{get;set;}
}
公共类事物B:IB
{
公共字符串PropOnB{get=>“IB”;set=>抛出新的NotImplementedException();}
}
公共类物品a:IA
{
公共字符串PropOnA{get=>“IA”;set=>抛出新的NotImplementedException();}
}
公共类内容C:IC
{
公共字符串PropOnC{get=>“IC”;set=>抛出新的NotImplementedException();}
}
内部静态类程序
{
私有静态void Main(字符串[]args)
{
var things=新列表{
新事物a(),
新事物b()/,
//新事物
};
foreach(事物中的事物)
{ 
var strategy=WriterFactory.GetStrategy(thing);//如果存在策略对象,则从'registry'获取该对象
strategy.Execute();
}
}
}

如果您很少添加新的
IMaster
专门化,但经常添加新的操作或需要确保操作提供程序(如writer)需要支持所有专门化,则是完美的选择

否则,您基本上需要某种服务定位器和注册协议来将操作提供者/策略映射到
IMaster
专业化

一种方法是定义通用接口,如
IMasterWriter,其中T:IMaster
,然后可以像定义映射的
IBWriter:IMasterWriter
那样实现

从这一点上讲,您只需要一种使用反射的机制来为给定类型的
IMaster
找到特定的
IMasterWriter
实现者,并决定如果缺少该实现者该怎么做。您可以尽早扫描程序集,以便在启动时检测缺少的实现,而不是在以后失败。

谢谢您的帮助
 public interface IWriterStrategy
{
    void Execute();
}

public class WriterA : IWriterStrategy
{
    private readonly IA _thing;

    public WriterA(IA thing)
    {
        _thing = thing;
    }
    public void Execute()
    {
        Console.WriteLine(_thing.PropOnA);
    }
}

public class WriterB : IWriterStrategy
{
    private readonly IB _thing;
    public WriterB(IB thing)
    {
        _thing = thing;
    }
    public void Execute()
    {
        Console.WriteLine(_thing.PropOnB);
    }
}



public static class WriterFactory
{
    public static List<(Type Master, Type Writer)> RegisteredWriters = new List<(Type Master, Type Writer)>
        {
           (typeof(IA),  typeof(WriterA)),
           (typeof(IB),  typeof(WriterB))
        };
    public static IWriterStrategy GetStrategy(IMaster thing)
    {
        (Type Master, Type Writer) writerTypeItem = RegisteredWriters.Find(x => x.Master.IsAssignableFrom(thing.GetType()));
        if (writerTypeItem.Master != null)
        {
            return (IWriterStrategy)Activator.CreateInstance(writerTypeItem.Writer, thing);
        }
        throw new Exception("Strategy not found!");
    }
}

public interface IMaster
{
    //Some properties
}

public interface IA : IMaster
{
    string PropOnA { get; set; }
}

public interface IB : IMaster
{
    string PropOnB { get; set; }
}

public interface IC : IMaster
{
    string PropOnC { get; set; }
}

public class ThingB : IB
{
    public string PropOnB { get => "IB"; set => throw new NotImplementedException(); }
}

public class ThingA : IA
{
    public string PropOnA { get => "IA"; set => throw new NotImplementedException(); }
}

public class ThingC : IC
{
    public string PropOnC { get => "IC"; set => throw new NotImplementedException(); }
}

internal static class Program
{
    private static void Main(string[] args)
    {
        var things = new List<IMaster> { 
            new ThingA(),
            new ThingB()//,
            //new ThingC()
        };



        foreach (var thing in things)
        { 
            var strategy = WriterFactory.GetStrategy(thing);  //this gets the strategy object from our `registry` if one exists
            strategy.Execute();
        }
    }
}