关于c#:使用泛型类型类继承的意外方法暴露

Unintended method exposure using inheritance with a generics typed class

标题我已经尽力了。我想要完成的是带有依赖注入的分层模块化。这种设计模式是否好是另一个论坛的问题。

因为我使用依赖注入,所以我有接口/实现对。这是顶级接口:

1
2
3
4
public interface IConfiguration< T > where T : ConfigData
{
    T GetConfig();
}

其中 ConfigData 是一个简单的类,它公开 get/set 属性,如 LogLevelEnvironment

接口有一个基本实现:

1
2
3
4
5
6
7
8
9
public abstract class ConfigurationBase< T > : IConfiguration
{
    protected ConfigData Config { get; set; }

    public T GetConfig()
    {
        return Config as T;
    }
}

现在是依赖注入部分!我有几个分层继承的接口/实现对。此外,它们的 protected Config 属性还在每个后续子类中公开了更多属性。这是我的接口/实现签名:

1
2
3
4
5
6
7
8
public interface IGeneralConfiguration : IConfiguration<GeneralConfigData>
public class GeneralConfiguration : ConfigurationBase<GeneralConfigData>, IGeneralConfiguration

public interface ILoginConfiguration : IConfiguration<LoginConfigData>, IGeneralConfiguration
public class LoginConfiguration : ConfigurationBase<LoginConfigData>, ILoginConfiguration

public interface IAppConfiguration : IConfiguration<AppConfigData>, ILoginConfiguration
public class AppConfiguration : ConfigurationBase<AppConfigData>, IAppConfiguration

请注意,配置数据元素的继承方案是 ConfigDataGeneralConfigDataLoginConfigDataAppConfigData。配置数据元素只是在每个子项中公开更多特定于登录/应用程序等的属性(如 UsernameStartUri)。

现在,我可以在我的所有模块中使用这个配置概念。就依赖注入而言,解析 IGeneralConfigurationILoginConfigurationIAppConfiguration 将产生完全相同的实例。但是,现在通用模块只需要解析IGeneralConfiguration,特定于登录的模块只需要解析ILoginConfiguration,而特定于应用程序的模块可以解析IAppConfiugration,所有这些都可以访问其特定的部分配置数据他们试图处理的问题。这种模块化允许我创建更小的侧应用程序,这些应用程序可以重用来自主应用程序的模块,而无需进行大量自定义编码(例如,我可以重用登录模块而无需引用特定于应用程序的模块),只要我稍微改变我的依赖注册。

如果你到现在为止还和我在一起,这个模型的唯一问题是在我所有的子类中(继承自 ConfigurationBase<T>),它们都需要来自它们上面的接口的 ConfigData() 实现.这意味着 class LoginConfiguration 需要 public GeneralConfigData GetConfig() 的方法定义,class AppConfiguration 需要 public GeneralConfigData GetConfig()LoginConfigData GetConfig() 的方法定义。

很好。我这样做。现在,在我的应用程序特定模块中,出现编译器错误。在我的类字段定义中,我有 private IAppConfiguration _appConfiguration;。稍后在一个方法中,我引用了它:

1
var element = _appConfiguration.GetConfig().AppSpecificConfigElement;

编译器很困惑,说

the call is ambiguous between the following or properties 'IConfiguration.GetConfig()' and 'IConfiguration.GetConfig()'

为什么编译器没有看到类型是 IAppConfiguration 并定义对 AppConfigurationGetConfig() 的调用(其中 T 定义为 AppConfigData)?

有没有一种明显的方法可以使用我的方案来消除对 GetConfig() 的调用的歧义?


如果我理解正确,那么您刚才所做的是,除了无法自动解析的返回值之外,您有两个具有相同签名的方法。编译器不会(也不能)遍历从 ConfigData 派生的所有子类以确定 AppSpecificConfigElement 属于 AppConfiguration 并基于此选择重载 - 即使这样做,您也可以拥有多个具有 AppSpecificConfigElement 属性的类所以它不会更明智。您需要帮助编译器了解您的需求,方法是键入 _appConfiguration 到正确的类型,或者首先在语句中使用 ConfigData 的类型化后代而不是 var 然后获取属性。

在这两种情况下,我认为您严重过度设计,我建议您退后一步,重新考虑您的方法。正如@zaitsman 所说,这些对象应该是 POCO,并且具有不同的加载器(数据库、文件系统,...),实现简单的 Load/Save 接口,然后可以根据上下文传递给 DI。