簡體   English   中英

使用泛型將接口類型映射到類

[英]Using generics to map interface types to classes

我的應用程序中有幾個Get____Factory方法,我想將它們與泛型合並,但我仍在調整C#,並且a)不是100%確定泛型是正確的方法,並且b)仍在學習C#的處理方式仿制葯。

我最終將擁有工廠接口及其類的字典/地圖。 我不僅希望將所有工廠合並為易於訪問的方法,而且還需要允許插件作者注冊自己的工廠(並以這種方式訪問​​它們)。

我開始是這樣的:

注意:最終將有一個字典或將接口類型映射到其實現的方法-if / else條件是丑陋且暫時的,而僅僅是一種測試方法。

public T GetFactory<T>() where T : IFactory {
    var t = typeof(T);

    if (t.Equals(typeof(IRecipeFactory))) {
        var factory = new RecipeFactory();
        return factory;
    }

    else if (t.Equals(typeof(IItemFactory))) {
        var factory = new ItemFactory();
        return factory;
    }

    else if (t.Equals(typeof(ITileFactory))) {
        var factory = new TileFactory();
        return factory;
    }
}

由於Cannot implicitly convert type 'RecipeFactory' to 'T'失敗,因此這將不起作用。 從長遠來看,我將沒有條件,但寧願按其類型查找該類。 但是,在我無法找到演員表問題的解決方案之前,這兩種方法都不起作用。

根據其他答案,我嘗試了雙InvalidCastException: Cannot cast from source type to destination type.(T) (object) ),但是InvalidCastException: Cannot cast from source type to destination type.出現此錯誤InvalidCastException: Cannot cast from source type to destination type.

要么這是一個糟糕的體系結構,要么我使用了不正確的泛型。

由於該方法返回T您將在出站時將對象強制轉換為T 為此,您必須將factoryIFactory

public T GetFactory<T>() where T : IFactory
{
    var t = typeof(T);

    if (t.Equals(typeof(IRecipeFactory)))
    {
        IFactory factory = new RecipeFactory();
        return (T)factory;
    }

    if (t.Equals(typeof(IItemFactory)))
    {
        IFactory factory = new ItemFactory();
        return (T)factory;
    }

    if (t.Equals(typeof(ITileFactory)))
    {
        IFactory factory = new TileFactory();
        return (T)factory;
    }

    throw new InvalidOperationException("Type not supported");
}

首先讓我說,您實際上正在看的是控制反轉(IOC)框架的簡單版本。 看一下Ninject或類似的東西,因為它的內核和綁定工廠幾乎正是您想要的。 它甚至允許附加元數據,因此您可以根據情況將同一接口解析為不同的實現,這在您有可能需要從Web數據源或緩存數據源中提取數據層時非常有用,例如。 大多數IOC框架還提供遞歸依賴關系解析,這意味着當某些實例的構造函數需要其他依賴關系時,基於可推斷的映射或默認映射,相同的依賴關系解析會一直出現在整個鏈中。

除此之外,要做自己想做的事情,您將需要使用Activator.CreateInstance ,它采用一個類型並根據該類型構造一個新實例。 您的字典映射在正確的軌道上。 將這兩部分結合在一起時,您不需要任何條件邏輯,也不需要提前知道或關心請求的類型。 當您感到舒適時,可以根據需要實際將依賴關系解析和實例化縮短到一行。

這是一個完全有效的示例(經過30秒鍾的測試),盡我所能,它可以完成您想做的事情:

using System;
using System.Collections.Generic;

namespace Generics
{
    // create some dummy interfaces and implementations. 
    // make sure everything inherits from the same type to allow for 
    // a generic return statement
    public interface IFactory
    {
        void DoStuff();
    }
    public interface IFactory1 : IFactory { }
    public class Factory1 : IFactory1
    {
        public void DoStuff()
        {
            Console.WriteLine("Factory1");
        }
    }
    public interface IFactory2 : IFactory { }
    public class Factory2 : IFactory2
    {
        public void DoStuff()
        {
            Console.WriteLine("Factory2");
        }
    }


    class Program
    {
        // create our binding mappings
        IDictionary<Type, Type> bindings = new Dictionary<Type, Type>()
            {
                // expose a way for plugins/etc to add to this. that part is trivial.
                {typeof(IFactory1), typeof(Factory1) },
                {typeof(IFactory2), typeof(Factory2) }
            };

        // a method to actually resolve bindings based on expected types
        public IFactory ResolveBinding<T>() where T : IFactory
        {
            Type requestedType = typeof(T);
            if (requestedType != null && bindings.ContainsKey(requestedType))
            {
                // use the activator to generically create an instance
                return (T) Activator.CreateInstance(bindings[requestedType]);
            }

            return null;
        }

        // test it out
        static void Main(string[] args)
        {
            Program demo = new Program();
            // test with two interfaces
            demo.ResolveBinding<IFactory1>().DoStuff(); // prints out "Factory1"
            demo.ResolveBinding<IFactory2>().DoStuff(); // prints out "Factory2"
            Console.ReadKey();
        }
    }
}

這里的解決方案與SC的解決方案有點不同。

public static class FactoryService
{
    private static readonly Dictionary<Type, Func<IFactory>> factories = new Dictionary<Type, Func<IFactory>>()
    {
        { typeof(IRecipeFactory), () => new RecipeFactory() },
        { typeof(IItemFactory), () => new ItemFactory() },
        { typeof(ITileFactory), () => new TileFactory() }
    };

    public static T GetFactory<T>() where T : IFactory
    {
        T factory = default(T);
        Type requestedType = typeof(T);

        if (factories.ContainsKey(requestedType))
        {
            factory = (T)factories[requestedType].Invoke();
        }

        return factory;
    }
}

public interface IFactory { }

public interface IRecipeFactory : IFactory { }

public interface IItemFactory : IFactory { }

public interface ITileFactory : IFactory { }

public class RecipeFactory : IRecipeFactory { }

public class ItemFactory : IItemFactory { }

public class TileFactory : ITileFactory { }

然后像這樣使用它:

IRecipeFactory rf = FactoryService.GetFactory<IRecipeFactory>();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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