[英]Choosing a Subclass without knowing the name of it in C#
编辑1:如果有人对此有更好的标题,请随时告诉我或自己编辑。
编辑2:感谢您的贡献,给出的答案几乎是我需要的一些调整,我很感谢这里的小内容。 今天真的学到了很多!
这里的小东西我现在要敲一下头了。
我想创建一个幻灯片,并希望Image对象本身具有逻辑。
该程序应该能够设置所需的过渡,或者只是一个随机的过渡,因此
我想用普通的东西创建一个过渡超类并进行特殊化
它在子类中。 所以我有Transitions.cs(当前没有任何代码)
并且没有派生类。 我希望它以添加单个.cs文件的方式
扩展Transitions.cs,并且不更改其他任何代码即可实现新的Transition。
我目前拥有的代码看起来像这样,但我想我
描述比代码更有用
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
}
}
我有一些类似静态东西的想法可以解决
看起来像这样,但是我想它不起作用
public class Transitions : MonoBehaviour {
public static int TransitionID;
protected static int SubclassCount;
protected static void SetID()
{
TransitionID = Transitions.SubclassCount;
Transitions.SubclassCount++;
}
}
我确实研究了状态设计模式,但是我不想实现它,因为我只需要选择一次状态并使其短暂。 图像对象本身的寿命只有大约几秒钟。 我不想执行通常的if嵌套,或者只是将所有代码放入SlideImages.cs中。 是否有任何良好的指导或对继承以及此类内容非常深入的内容?
欣赏所有输入。
对于您想做的事情有两种简单的解决方案。 您的基本问题是,您希望能够向程序中动态添加功能,但又不想知道要使用哪些功能。 实现此目的的最简单方法是使用Actions
而不是子类化。 当您想添加另一个过渡时,只需更新一个动作列表,如下所示:
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]();
}
}
上面的方法很简单,但是所有逻辑(或至少根据对过渡实现实际工作的位置对逻辑的引用)都放在一个位置。 根据您要添加的过渡数量以及有多少开发人员正在使用此代码库,它也有可能变得非常混乱。 它还要求有权访问完整代码库的人员添加所有功能,并且每次添加新转换时都需要重新编译。
从长远来看,更复杂但更可维护和更灵活的方法是使用模块(或出于我们的目的使用插件)。 该方法中的每个转换都由共享模块或特定模块提供,并且是基本AbstractTransition
类的子类,或者是ITransition
接口的实现,具体取决于您要执行的操作。 使用生成后任务将所有模块dll放置在主程序可访问的单个目录中(获得许可的其他任何人也可以在其中放置过渡模块dll)。 程序启动时,它将动态加载该目录中的所有dll(只要在该目录中添加了正确的dll,就无需重新编译即可),并提取实现该接口的所有类。 这些接口实现中的每一个都被实例化并放入数据结构中,之后您可以使用与上述PerformTransition
方法类似的策略来基于ID而不是索引执行一个或多个随机操作。 如果您愿意,我可以使用该结构的示例来编辑此问题。
编辑:您尚未要求它,但是这是一个带有插件/模块的示例。
首先,创建一个项目以加载和运行转换。 本示例将使用一个名为ModuleDemo
的项目。 给它一个主要的方法是这样的:
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
}
您会注意到该方法引用了AbstractTransition
类。 现在,我们为此创建一个单独的TransitionModule
项目。 这是模块将引用的项目:
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
}
}
现在,我们有了要实现的插件的抽象过渡类和功能正常的插件加载器,我们可以继续创建一些过渡插件。
我在解决方案中为此创建了一个Modules
文件夹,但这并不重要。
FlipTransition
项目中的第一个模块:
using System;
using TransitionModule;
namespace FlipTransition
{
public class FlipTransition : AbstractTransition
{
public FlipTransition() : base(2)
{
}
public override void PerformTransition()
{
Console.WriteLine("Performing flip transition");
}
}
}
SlideTransition
项目中的第二个模块:
using System;
using TransitionModule;
namespace SlideTransition
{
public class SlideTransition : AbstractTransition
{
public SlideTransition() : base(1)
{
}
public override void PerformTransition()
{
Console.WriteLine("Performing slide transition");
}
}
}
请注意,每个项目都需要引用TransitionModule
项目,但主项目不需要了解其他任何项目。
现在,我们有2个转换插件和一个插件加载器。 由于插件加载程序将要从Modules
目录中加载Modules
,因此请转到主项目的/bin/Debug
目录并创建一个Modules
目录。 也将过渡插件项目的/bin/Debug
目录中的所有dll复制到该目录中。 所有这些都可以在以后通过生成后任务自动执行。
继续运行程序。 您应该获得如下输出:
Loaded transition with id 2
Performing flip transition
Loaded transition with id 1
Performing slide transition
您可以做很多事情来使其更加优雅,但这至少是一个简单的示例,说明如何使用基于插件的体系结构来提供所需的内容。
您可以尝试使用抽象类,创建用于图像转换的基本抽象类;
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];
}
}
然后,创建新的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);
}
}
这使您可以根据需要构建一些自定义过渡。
-编辑-您当然会在调用GetNextImage方法之前填充字典ImageDictionary。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.