Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#无铸造的多形设计_C#_Polymorphism - Fatal编程技术网

C#无铸造的多形设计

C#无铸造的多形设计,c#,polymorphism,C#,Polymorphism,我有一个生成器类,它可以生成具有不同接口的对象,这些接口的概率不同。生成器生成的所有对象的类型均为基类基类是一个抽象基类 假设接口是I1,I2 我有另一个类Resolver,它有两个接口的多态方法,如下所示: Resolve(I1 myObj){//code for I1} Resolve(I2 myObj){//code for I2} 主类如下所示: 基类事件=Generator.generate()//事件是实现I1或I2。在运行时之前不知道什么接口。 解析程序。解析(事件)//这里我得

我有一个生成器类,它可以生成具有不同接口的对象,这些接口的概率不同。生成器生成的所有对象的类型均为
基类
<代码>基类是一个抽象基类

假设接口是
I1
I2

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

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

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

主类如下所示:

基类事件=Generator.generate()//事件是实现I1或I2。在运行时之前不知道什么接口。
解析程序。解析(事件)//这里我得到了一个错误,因为事件是基类类型,而不是I1或I2类型。

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

EDIT我调整了我的答案,因为我第一次没有正确理解这个问题

我认为,如果不使用强制类型转换,就无法实现您想要的目标。据我所知,只要您通过基本类型引用从
Generator.generate()
获得的对象,就不可能在不强制转换的情况下再次通过其专用类型访问该对象

我可以想出两种对你有意思的选择。一种是使用C#7模式匹配(有点像使用强制转换),另一种是使用
动态

模式匹配

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();
        }
    }
}
动态

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();
        }
    }
}
编辑我调整了答案,因为我第一次没有正确理解问题

我认为,如果不使用强制类型转换,就无法实现您想要的目标。据我所知,只要您通过基本类型引用从
Generator.generate()
获得的对象,就不可能在不强制转换的情况下再次通过其专用类型访问该对象

我可以想出两个你可能感兴趣的选择。一种是使用C#7模式匹配(有点像使用强制转换),另一种是使用
动态

模式匹配

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();
        }
    }
}
动态

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

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

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);
我们可以更进一步,为解析器创建一个接口,这样我们就可以模拟它进行单元测试,并充分利用DI模式

public interface IResolver
{
    void Resolve(I1 i) { //... }
    void Resolve(I2 i) { //... }
}
然后我们改变了IResolvable的定义

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

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

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);
我们可以更进一步,为解析器创建一个接口,这样我们就可以模拟它进行单元测试,并充分利用DI模式

public interface IResolver
{
    void Resolve(I1 i) { //... }
    void Resolve(I2 i) { //... }
}
然后我们改变了IResolvable的定义

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

下面的代码演示了不需要强制转换的虚拟函数方法

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

下面的代码演示了不需要强制转换的虚拟函数方法

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

是的,您可以有一个公共接口“I”,它用作基类的基。我将有一个虚拟函数,它将在分别从I1和I2派生的自定义类中被重写。例如,C1来自I1,C2来自I2。接下来,在生成器中生成C1或C2。然后不需要检查类型,只需调用虚拟函数。它将根据类的类型执行不同的代码。让我知道这是否有意义,这样我可以写一个更具说明性的答案。听起来很有趣。是的。很抱歉耽搁了,请检查我的答案。是的,您可以有一个公共接口“I”,它用作基类的基类。我将有一个虚拟函数,它将在分别从I1和I2派生的自定义类中被重写。例如,C1来自I1,C2来自I2。接下来,在生成器中生成C1或C2。然后不需要检查类型,只需调用虚拟函数。它将根据类的类型执行不同的代码。让我知道这是否有意义,这样我可以写一个更具说明性的答案。听起来很有趣。是的。很抱歉耽搁了,请检查我的答案。和我的问题很相似,但不一样。在我的例子中,解析器将有许多解析方法,每个I1,I2。。。接口。在不同的方法中有不同的代码。@Farseer:请看我调整后的答案。我不会这么快就求助于
dynamic
。任何涉及<代码>动态的问题都必须在运行时完全解决,这会变得更慢,而且编译器无法保护您避免明显的错误。VuVirt的建议(实质上为
基类
添加了一个虚拟的
Resolve
方法)允许编译器验证该方法是否存在于所有涉及的类中,并且您不必进行任何类型检查。与我的问题非常类似,但不同。在我的例子中,解析器将有许多解析方法,每个I1,I2。。。接口。在不同的方法中有不同的代码。@farsear:请参阅我调整过的答案。我不会这么快地求助于
dynamic
的。任何涉及<代码>动态的问题都必须在运行时完全解决,这会变得更慢,而且编译器无法保护您避免明显的错误。VuVirt的建议(实质上为
基类
添加了一个虚拟的
Resolve
方法)允许编译器验证该方法是否存在于所有涉及的类中,并且您不必进行任何类型检查。很好,我愚蠢的问题是它是否应该使用而不是基类