简体   繁体   English

在C#中选择子类而不知道其名称

[英]Choosing a Subclass without knowing the name of it in C#

Edit 1:If anyone has a better Title for that, feel free to tell me or edit it yourself. 编辑1:如果有人对此有更好的标题,请随时告诉我或自己编辑。
Edit 2: Thanks for your contribution guys, the answer given is almost what I need with some tweaks and I'm thankful for the small stuff here. 编辑2:感谢您的贡献,给出的答案几乎是我需要的一些调整,我很感谢这里的小内容。 Really learnt much today! 今天真的学到了很多!

Little stuff here that I'm banging my head on for a while now. 这里的小东西我现在要敲一下头了。
I want to create a Slideshow and want the logic in the Image objects itself. 我想创建一个幻灯片,并希望Image对象本身具有逻辑。

The programm should be able to set a desired transition or just a random one so 该程序应该能够设置所需的过渡,或者只是一个随机的过渡,因此
I wanted to create a Transition Superclass with the general stuff and spezialize 我想用普通的东西创建一个过渡超类并进行特殊化
it in the subclasses. 它在子类中。 So I have Transitions.cs (with no Code currently inside it) 所以我有Transitions.cs(当前没有任何代码)
and no derived class. 并且没有派生类。 I want it to be in the way of adding a single .cs file 我希望它以添加单个.cs文件的方式
extending Transitions.cs and not change any other code to implement a new Transition. 扩展Transitions.cs,并且不更改其他任何代码即可实现新的Transition。

The Code I currently have looks something like this but I guess my 我目前拥有的代码看起来像这样,但我想我
description is more helpful than the code 描述比代码更有用

public class SlideImages : MonoBehaviour {

    Image image;
    Image nextImage;
    int tracker;

    private void Transition(int ID)
    {
        /*Something to choose a transition based on the ID
        *Transitions.cs is the superclass of all different transitions
        *f.e. Ken-Burns Effect, or scattered Transition which all extend from it
        */
    }

    ~SlideImages()
    {
        //TODO: Pop and Push
    }
}

I had the idea of something along the lines of static stuff to workaround that 我有一些类似静态东西的想法可以解决
looks like this but it doesn't work I suppose 看起来像这样,但是我想它不起作用

public class Transitions : MonoBehaviour {

    public static int TransitionID;
    protected static int SubclassCount;

    protected static void SetID()
    {
        TransitionID = Transitions.SubclassCount;
        Transitions.SubclassCount++;
    }
}

I did look into the state design pattern but I don't want to implement it as I just need the state to be chosen once and shortlived. 我确实研究了状态设计模式,但是我不想实现它,因为我只需要选择一次状态并使其短暂。 The Image Objects themself only have a lifetime of around a few seconds. 图像对象本身的寿命只有大约几秒钟。 I don't want to do the usual if-nesting or just put all the code inside the SlideImages.cs. 我不想执行通常的if嵌套,或者只是将所有代码放入SlideImages.cs中。 Is there any good guidance to it or stuff that goes very indepth into inheritance and such stuff? 是否有任何良好的指导或对继承以及此类内容非常深入的内容?

Appreciate all the input. 欣赏所有输入。

There are two straight-forward solutions to what you want to do. 对于您想做的事情有两种简单的解决方案。 Your basic problem is that you want to be able to dynamically add functionality to your program but you don't want to have knowledge of what has been added in order to use it. 您的基本问题是,您希望能够向程序中动态添加功能,但又不想知道要使用哪些功能。 The most hack-ish way of doing it is to use Actions instead of subclassing. 实现此目的的最简单方法是使用Actions而不是子类化。 When you want to add another transition you just update an actions list like this: 当您想添加另一个过渡时,只需更新一个动作列表,如下所示:

public static class Transitions
{
    private static Action[] TransitionStrategies = new Action[]
    {
        () => { /* One way of performing a transition */ },
        () => { /* Another way of performing a transition */ },
        () => { /* Keep adding methods and calling them here for each transition type */ }
    }

    public static void PerformTransition(int? transitionIndex = null)
    {
        int effectiveIndex;

        // if the transition index is null, use a random one
        if (transitionIndex == null)
        {
            effectiveIndex = new Random().Next(0, TransitionStrategies.Length);
        }
        else
        {
            effectiveIndex = transitionIndex.Value;
        }

        // perform the transition
        TransitionStrategies[effectiveIndex]();

    }
}

The above approach is simple but all of the logic (or at least references to the logic depending on where you implement the actual work for the transitions) is in one place. 上面的方法很简单,但是所有逻辑(或至少根据对过渡实现实际工作的位置对逻辑的引用)都放在一个位置。 It also has the potential to get quite messy depending on how many transitions you are adding and how many developers are touching this codebase. 根据您要添加的过渡数量以及有多少开发人员正在使用此代码库,它也有可能变得非常混乱。 It also requires all functionality to be added by someone with access to the full codebase and requires a recompilation each time new transitions are added. 它还要求有权访问完整代码库的人员添加所有功能,并且每次添加新转换时都需要重新编译。

A more complex but much more maintainable and flexible approach in the long term is to use modules (or plugins for our purposes). 从长远来看,更复杂但更可维护和更灵活的方法是使用模块(或出于我们的目的使用插件)。 Each transition in that approach is provided by either a shared module or a specific module and is a subclass of a base AbstractTransition class or an implementation of an ITransition interface depending on how you want to go about doing that. 该方法中的每个转换都由共享模块或特定模块提供,并且是基本AbstractTransition类的子类,或者是ITransition接口的实现,具体取决于您要执行的操作。 Use post-build tasks to place all of your module dlls in a single directory accessible to your main program (anyone else given permission can put transition module dlls there too). 使用生成后任务将所有模块dll放置在主程序可访问的单个目录中(获得许可的其他任何人也可以在其中放置过渡模块dll)。 When your program launches, it dynamically loads all dlls from that directory (no recompilation required when new transitions are added as long as the right dlls are in that directory) and pulls out all of the classes implementing that interface. 程序启动时,它将动态加载该目录中的所有dll(只要在该目录中添加了正确的dll,就无需重新编译即可),并提取实现该接口的所有类。 Each of those interface implementations are instantiated and placed into a data structure after which you can use a similar strategy to the above's PerformTransition method to perform a random one or one based on an ID instead of an index. 这些接口实现中的每一个都被实例化并放入数据结构中,之后您可以使用与上述PerformTransition方法类似的策略来基于ID而不是索引执行一个或多个随机操作。 I can edit this question with an example of that structure if you would like. 如果您愿意,我可以使用该结构的示例来编辑此问题。

Edit: You didn't ask for it yet, but here's an example with plugins/modules. 编辑:您尚未要求它,但是这是一个带有插件/模块的示例。

First, create a project to load and run the transitions. 首先,创建一个项目以加载和运行转换。 This example will use a project called ModuleDemo . 本示例将使用一个名为ModuleDemo的项目。 Give it a main method like this: 给它一个主要的方法是这样的:

static void Main(string[] args)
{
    // create a list to hold the transitions we load
    List<AbstractTransition> transitions = new List<AbstractTransition>();

    // load each module we find in the modules directory
    foreach (string dllFilepath in Directory.EnumerateFiles("Modules", "*.dll"))
        // this should really read from the app config to get the module directory                
    {
        Assembly dllAssembly = Assembly.LoadFrom(dllFilepath);

        transitions.AddRange(dllAssembly.GetTypes()
            .Where(type => typeof(AbstractTransition).IsAssignableFrom(type))
            .Select(type => (AbstractTransition) Activator.CreateInstance(type)));
    }

    // show what's been loaded
    foreach (AbstractTransition transition in transitions)
    {
        Console.WriteLine("Loaded transition with id {0}", transition.TransitionId);

        // execute just to show how it's done
        transition.PerformTransition();
    }

    Console.Read(); // pause
}

You'll notice that the method references an AbstractTransition class. 您会注意到该方法引用了AbstractTransition类。 Let's create a separate TransitionModule project for that now. 现在,我们为此创建一个单独的TransitionModule项目。 This is the project that the modules will reference: 这是模块将引用的项目:

namespace TransitionModule
{
    public abstract class AbstractTransition
    {        
        public readonly int TransitionId;
        public abstract void PerformTransition();

        protected AbstractTransition(int transitionId)
        {
            TransitionId = transitionId;
        }

        // you can add functionality here as you see fit
    }
}

Now that we have an abstract transition class for the plugins to implement and a functioning plugin loader, we can go ahead and create a few transition plugins. 现在,我们有了要实现的插件的抽象过渡类和功能正常的插件加载器,我们可以继续创建一些过渡插件。

I created a Modules folder for this in my solution but it doesn't really matter. 我在解决方案中为此创建了一个Modules文件夹,但这并不重要。

First module in a FlipTransition project: FlipTransition项目中的第一个模块:

using System;
using TransitionModule;

namespace FlipTransition
{
    public class FlipTransition : AbstractTransition
    {
        public FlipTransition() : base(2)
        {
        }

        public override void PerformTransition()
        {
            Console.WriteLine("Performing flip transition");
        }
    }
}

Second module in a SlideTransition project: SlideTransition项目中的第二个模块:

using System;
using TransitionModule;

namespace SlideTransition
{
    public class SlideTransition : AbstractTransition
    {
        public SlideTransition() : base(1)
        {
        }

        public override void PerformTransition()
        {
            Console.WriteLine("Performing slide transition");
        }
    }
}

Note that each of those projects needs to reference the TransitionModule project but the main project doesn't need to know about any of the other projects. 请注意,每个项目都需要引用TransitionModule项目,但主项目不需要了解其他任何项目。

Now we have 2 transition plugins and a plugin loader. 现在,我们有2个转换插件和一个插件加载器。 Since the plugin loader is going to load the modules from a Modules directory, go to the /bin/Debug directory of the main project and make a Modules directory. 由于插件加载程序将要从Modules目录中加载Modules ,因此请转到主项目的/bin/Debug目录并创建一个Modules目录。 Copy all of the dlls from the /bin/Debug directories of the transition plugin projects into that directory as well. 也将过渡插件项目的/bin/Debug目录中的所有dll复制到该目录中。 All of this can be automated with post-build tasks later on. 所有这些都可以在以后通过生成后任务自动执行。

Go ahead and run the program. 继续运行程序。 You should get output like this: 您应该获得如下输出:

Loaded transition with id 2
Performing flip transition
Loaded transition with id 1
Performing slide transition

There's a lot you can do to make this more elegant, but this is at least a simple example of how you can use a plugin-based architecture to provide what you need. 您可以做很多事情来使其更加优雅,但这至少是一个简单的示例,说明如何使用基于插件的体系结构来提供所需的内容。

You could try playing around with abstract classes, create a base abstract class for image transitioning; 您可以尝试使用抽象类,创建用于图像转换的基本抽象类;

public abstract class ImageTransition
{
    protected int imageId { get; set; }
    public Dictionary<int, Image> ImageDictionary { get; set; }

    protected abstract void TransitionToNextImageId();

    public Image GetNextImage()
    {
        TransitionToNextImageId();
        return ImageDictionary[imageId];
    }
}

You then create new Transition types that inherit from this base class and have their own implementation of the TransitionToNextImageId method; 然后,创建新的Transition类型,这些类型从该基类继承并具有自己的TransitionToNextImageId方法的实现;

public class InTurnImageTransition : ImageTransition
{
    protected override void TransitionToNextImageId()
    {
        if(this.imageId < ImageDictionary.Count)
            this.imageId ++;
    }
}

public class RandomImageTransition : ImageTransition
{
    protected override void TransitionToNextImageId()
    {
        imageId = new Random().Next(0, ImageDictionary.Count);
    }
}

This allows you to build up some custom transitions however you wish. 这使您可以根据需要构建一些自定义过渡。

-Edit- You would of course fill the dictionary ImageDictionary before calling the GetNextImage method. -编辑-您当然会在调用GetNextImage方法之前填充字典ImageDictionary。

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

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