如何以通用方式结合两个类?

时间:2012-10-16 21:56:08

标签: c# generics type-inference type-safety

我有ShipShampooHorse等实体的课程,每个实体都有一个类似ShipManagerShampooManager,{的经理类所有经理类都实现HorseManager,实体实现IManager。{1}}等。

现在我编写了一个静态函数来保存看起来像的实体:

IEntity

这里的不雅之处在于我必须像public static bool Save<S, T>(S entity, string msg) where S : IEntity where T : IManager<S>, new() { string possibleError; switch (new T().Save(entity, out possibleError)) { //--------------------- } return true; } 那样打电话给Save等。我希望拥有的是这样的:

Save<Radio, RadioManager>

有几种方法可以做到这一点,但我希望有一些涉及泛型和类型推断。我认为通过设计将实体类与相应的管理器类耦合以实现某些类型安全性会很好。

在扩展方法的帮助下,我可以做的就是:

public static bool Save<T>(T entity, string msg) where T : IEntity
{
    string possibleError;
    switch ((/*find manager here*/).Save(entity, out possibleError))
    {
        //---------------------
    }
    return true;
}

所以我可以致电:

public static bool Save<T>(this IManager<T> mgr, T entity, string msg) where T : IEntity
{
    string possibleError;
    switch (mgr.Save(entity, out possibleError))
    {
        //---------------------
    }
    return true;
}

但是在这里我总是需要实例化FooManager fMgr = new FooManager(); fMgr.Save(foo, "success"); ,然后在其实例上调用IManager方法。我希望避免那么多重复的代码,并赋予静态函数的职责。 如何设计类以在SaveIManager之间建立关系,以便自动推断实体经理?

编辑:请注意,我没有把经理类中的IEntity方法移动到实体类(这会让生活变得更轻松)。我们的整个设计基于一个实体类和相应的管理器类。所以我想坚持下去。

2 个答案:

答案 0 :(得分:4)

FooManager的客户端是否关心它是一个FooManager,或者它是一个IManager&lt; Foo&gt; ?如果它只是想要IManager&lt; Foo&gt;,您可能想要查看AbstractFactory模式。您的工厂将负责按需实例化/检索正确的IManager。在工厂就位后,您的保存方法看起来像这样

public static bool Save<S>(S entity, string msg) 
  where S : IEntity
  {     
     string possibleError;     
     switch (ManagerFactory.GetManagerFor<S>().Save(entity, out possibleError))     
     {
       //---------------------     
     }     
     return true; 
  } 

实现ManagerFactory的最简单方法是使用服务定位器/依赖注入器,让它自动发现您的IManager&lt; T&gt;实现。然后你的GetManagerFor方法只需要从DI容器中请求一个实例。例如,以下是AutoFac

的使用方法
var dataAssembly = Assembly.GetExecutingAssembly();

builder.RegisterAssemblyTypes(dataAssembly)
    .Where(t => t.Name.EndsWith("Manager"))
    .AsClosedTypesOf(typeof(IManager<>);

这将导致autofac在当前程序集中查找名称中以“Manager”结尾的所有类,并将其注册为IManager&lt; T&gt;的封闭类型。因此它会找到FooManager并将其注册为IManager&lt; Foo&gt;的实例。

现在ManagerFactory只需要调用

return container.Resolve<IManager<Foo>>()

你是金色的。我不会为你写你的申请,但这应该足以让你去。阅读关于AutoFac的文档,它非常强大,因为它也可以使用依赖注入为您构建对象,并且它是一个很好的工具。

答案 1 :(得分:0)

以下是我如何解决它。

我在Manager中创建了一个函数IEntity,如下所示:

IManager<T> Manager<T>() where T : IEntity;

现在每当我在任何实体类中实现IEntity时,我都被迫实现各自的Manager。例如。

public class Foo : IEntity
{
    public IManager<T> Manager<T>() where T : IEntity
    {
        return (IManager<T>)new FooManager();
    }
}

现在我可以致电:

public static bool Save<T>(T entity, string msg) where T : IEntity, new()
{
    string possibleError;
    switch (entity.Manager<T>().Save(entity, out possibleError))
    {
        //--------------------------------------
    }
    return true;
}

不是最好的设计,但这可以胜任......