Polymorphim:如何创建Interface的动态实例

Kar*_*ala 2 c# polymorphism switch-statement

我正在阅读本文以删除c#中的切换案例并使用多态来实现它.

https://refactoring.guru/replace-conditional-with-polymorphism

这是我的代码:

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

namespace Consolas
{
    public class Program
    {
        static void Main(string[] args)
        {
            var animalType = "Dog"; //consider this as an argument supplied to the app
            //How to create dynamic instance for IAnimal ???
            //Is Activator.CreateInstance the only way to achieve it ??
            //IAnimal animal = ..what here ?
            //animal.Bark();
        }
    }

    public interface IAnimal
    {
        void Bark();
    }

    public class Dog: IAnimal
    {
        public void Bark()
        {
            Console.WriteLine("Bow Bow");
        }
    }

    public class Cat: IAnimal
    {
        public void Bark()
        {
            Console.WriteLine("Meow Meow");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如何为该接口创建实例,以便它可以动态调用该Bark方法.

有人可以提供最好的方法,而不仅仅是一个解决方案.

KMo*_*ssa 5

考虑使用工厂模式来实现这一点,一个例子是这样的:

public class AnimalFactory
{
    public IAnimal CreateAnimal(string animalType)
    {
         //Here you can either have a switch statement checking for
         //type, or use Type.GetType(animalType) and then create an
         //instance using the Activator - but in the latter case you will
         //need to pass in the exact type name of course 

         //PS. You can also use an IoC container to resolve all
         //implementations of IAnimal and have a distinguishing property
         //that you use here to select the type you want, but I think
         //that's a bit off topic so won't detail it here
    }
}

 static void Main(string[] args)
 {
        var animalType = "Dog";
        var amimal = new AnimalFactory().CreateAnimal(animalType);
        animal.Bark(); 
 }
Run Code Online (Sandbox Code Playgroud)

编辑

使用IoC容器(本例中为AutoFac)的一种方法是扫描程序集并注册IAnimal由类名称键入的所有实现(如果您注册单例实例,则可以通过接口的属性键入),类似于以下:

class Program
{
    public static IContainer _container;

    static void Main(string[] args)
    {
        //Register types
        Register();

        //Resolve a dog
        var dog = _container.ResolveKeyed<IAnimal>("Dog");
        //Resolve a cat
        var cat = _container.ResolveKeyed<IAnimal>("Cat");

        dog.Bark(); //Bow Bow
        cat.Bark(); //Meow Meow

        Console.Read();
   }

    static void Register()
    {
        //Get all types implementing IAnimal, you can of course scan multiple assemblies,
        //here I am only looking at the current assembly
        var types = Assembly.GetExecutingAssembly().GetTypes().Where(t => !t.IsInterface && t.IsAssignableTo<IAnimal>());

        var builder = new ContainerBuilder();
        foreach (var t in types)
        {
            //Use the type name as a key to the instance
            builder.RegisterType(t).Keyed<IAnimal>(t.Name)
              .InstancePerDependency(); //You want a new instance each time you resolve
        }          

        _container = builder.Build();            
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,您仍然可以将其重构为工厂PS.使用AutoFac的程序集扫描可能有更好的方法在程序集中注册所有类型,但我看不出任何方法将其与每种类型的键组合.