簡體   English   中英

在C#中選擇子類而不知道其名稱

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM