繁体   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