繁体   English   中英

C#无需铸造的多态设计

[英]C# polymorphous design without casting

我有Generator类,可以生成具有不同概率的不同接口的对象。 Generator生成的所有对象的类型都是BaseClass BaseClass是一个抽象基类。

可以说接口是I1I2

我还有另一个类Resolver ,该类具有两个接口的多态方法,如下所示:

Resolve(I1 myObj){//code for I1}

Resolve(I2 myObj){//code for I2}

主类如下所示: BaseClass event = Generator.generate(); //event is implements I1 or I2. Not known what interfaces until run time. Resolver.Resolve(event); //Here i got an error, because event is BaseClass type and not I1 or I2 type. BaseClass event = Generator.generate(); //event is implements I1 or I2. Not known what interfaces until run time. Resolver.Resolve(event); //Here i got an error, because event is BaseClass type and not I1 or I2 type.

有没有解决此问题的方法,而无需显式检查接口类型并将其强制转换为适当的接口。 我来自python背景,因此静态类型语言对我来说是新的。

考虑使用依赖项注入来允许事件对象调用解析程序本身。

public interface IResolvable
{
    void Resolve(Resolver resolver);
}

public interface I1 : IResolvable { //... }
public interface I2 : IResolvable { //... }

public class Resolver
{
    public void Resolve(I1 i) { //... }
    public void Resolve(I2 i) { //... }
}

public abstract class BaseClass : IResolvable 
{ 
    public abstract void Resolve(Resolver resolver);
    //... 
}

一个实现看起来像:

public class Implementation1 : BaseClass, I1
{
    public override void Resolver(Resolver resolver)
    {
         resolver.Resolve(this);
    }
    //...
}

然后调用它:

Resolver resolver = new Resolver();
IResolvable evnt = Generator.Generate();
evnt.Resolve(resolver);

我们可以更进一步,为Resolver创建一个接口,以便为单元测试目的而对其进行模拟,并充分利用DI模式。

public interface IResolver
{
    void Resolve(I1 i) { //... }
    void Resolve(I2 i) { //... }
}

然后我们更改IResolvable的定义

public interface IResolvable
{
    void Resolve(IResolver resolver);
}

编辑 我调整了答案,因为我第一次没有正确理解问题。

我认为,如果不使用强制转换,就无法完全实现您想要的目标。 据我了解,一旦您通过Generator.generate()的基类型引用了该对象,就无法通过其专用类型再次访问该对象而不进行转换。

我可以想到两种可能对您有趣的选择。 一种使用C#7模式匹配(有点像使用强制转换),另一种使用dynamic

模式匹配

using System;

namespace EventREsolver
{
    public interface IEvent { }

    public class Event1 : IEvent { }

    public class Event2 : IEvent { }

    public class Resolver
    {
        public void Resolve(IEvent theEvent)
        {
            switch (theEvent)
            {
                case Event1 e1: Resolve(e1); break;
                case Event2 e2: Resolve(e2); break;
                default: throw new ArgumentException("not a recognized type", nameof(theEvent));
            }   
        } 

        private void Resolve(Event1 theEvent)
        {
            Console.WriteLine("Resolve I1");
        }

        private void Resolve(Event2 theEvent)
        {
            Console.WriteLine("Resolve I2");
        }
    }

    public class Generator
    {
        int state = 0;

        public IEvent Generate()
        {
            if (state == 0)
            {
                state++;
                return new Event1();
            }
            return new Event2();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var generator = new Generator();
            var event1 = generator.Generate();
            var event2 = generator.Generate();

            var resolver = new Resolver();
            resolver.Resolve(event1);
            resolver.Resolve(event2);

            Console.ReadKey();
        }
    }
}

Dynamic

using System;

namespace EventREsolver
{
    public interface IEvent { }

    public class Event1 : IEvent { }

    public class Event2 : IEvent { }

    public class Resolver
    {
        public void Resolve(Event1 theEvent)
        {
            Console.WriteLine("Resolve I1");
        }

        public void Resolve(Event2 theEvent)
        {
            Console.WriteLine("Resolve I2");
        }
    }

    public class Generator
    {
        int state = 0;

        public IEvent Generate()
        {
            if (state == 0)
            {
                state++;
                return new Event1();
            }
            return new Event2();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var generator = new Generator();
            dynamic event1 = generator.Generate();
            dynamic event2 = generator.Generate();

            var resolver = new Resolver();
            resolver.Resolve(event1);
            resolver.Resolve(event2);

            Console.ReadKey();
        }
    }
}

这是一些代码,演示了不需要强制转换的虚函数方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication3
{
interface IBase
{
    void Function();
}

class BaseClass : IBase
{
    public virtual void Function()
    {
    }
}

interface I1: IBase
{

}

interface I2 : IBase
{

}

class C1: BaseClass, I1
{
    public override void Function()
    {
        Console.WriteLine("Hello from C1");
    }
}

class C2 : BaseClass, I1
{
    public override void Function()
    {
        Console.WriteLine("Hello from C2 !!!");
    }
}

static class Generator
{
    public static BaseClass generateC1()
    {
        return new C1();
    }

    public static BaseClass generateC2()
    {
        return new C2();
    }
}

class Program
{
    static void Main(string[] args)
    {
        BaseClass b1 = Generator.generateC1();
        b1.Function();

        Console.WriteLine("-------");

        BaseClass b2 = Generator.generateC2();
        b2.Function();

        Console.WriteLine("End!");
    }
}
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM