热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

Unintendedmethodexposureusinginheritancewithagenericstypedclass标题我已经尽力了。我想要完成的是带有依赖注入的分层模块

文章目录[隐藏]

  • Unintended method exposure using inheritance with a generics typed class

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),它们都需要来自它们上面的接口的 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() 的调用的歧义?

  • 试试这个:var element = ((IConfiguration)_appConfiguration).GetConfig??().AppSpecificConfig??Element;
  • 另外,作为旁注,您刚刚所做的事情将使追随您的人的生活变得非常痛苦。配置对象应该是 POCO,或者是具有简单界面的最大 POCO(即使只有当您坚持使用经典 .net 和类似桌面的东西时)。这允许通过 IoC 框架从任何源(db、文本文件、json、外部源)根据需要注入它们。如果您需要继承,您只需拥有 Config1 : Config2Config2 : Config3 链,并将相同的实例传递给 IoC。
  • 我没有得到抽象 ConfigurationBase 类的这一部分:protected ConfigData Config { get; set; } 如果有的话,它应该是 protected T Config { get; set; }
  • @zaitsman 问题的复杂性中丢失了一些细节。实现的 IConfiguration 继承链有两个目的。 (1) 在该层公开 Config POCO 和 (2) 公开特定于该层的配置方法,例如SaveLoginConfig() 代表 ILoginConfigurationLoadUserProfile() 代表 IAppConfiguration。我没有将其包含在问题中,因为我担心它会混淆细节,但知道我为什么这样做肯定会有所帮助。
  • 另外,@zaitsman,您的建议在语法上完全有效,但是强制转换违背了所有这些复杂性的目的。看起来您通常认为这种复杂性弊大于利(您可能完全正确)。我正在考虑将这个问题放在软件工程 SE 或 CodeReview SE 上以获得人们的意见。
  • @ZoharPeled 看到上面的两条评论 - 关键是每一层的复杂性(一般与登录与应用程序)都会(1)公开特定于该层的配置对象和(2)公开特定于该层的类似配置的方法. Config 受到保护,因为我不希望它被公开设置,但我确实希望子类可以访问它。 public T GetConfig() 旨在提供便利,因此如果我知道我正在使用登录或应用程序层,我将自动获得对已转换为适当类型的 ConfigData 元素的引用。
  • @MichaelPlautz 查看 explicit interface implementation。那或类型转换确实是您唯一的选择。


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

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

  • 您指出我想要的东西是不可能的。上网问,X 能做 Y 吗?是一回事,但要自信地说 X 不能做 Y,需要更多的知识和研究。



推荐阅读
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文介绍了使用postman进行接口测试的方法,以测试用户管理模块为例。首先需要下载并安装postman,然后创建基本的请求并填写用户名密码进行登录测试。接下来可以进行用户查询和新增的测试。在新增时,可以进行异常测试,包括用户名超长和输入特殊字符的情况。通过测试发现后台没有对参数长度和特殊字符进行检查和过滤。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • 解决VS写C#项目导入MySQL数据源报错“You have a usable connection already”问题的正确方法
    本文介绍了在VS写C#项目导入MySQL数据源时出现报错“You have a usable connection already”的问题,并给出了正确的解决方法。详细描述了问题的出现情况和报错信息,并提供了解决该问题的步骤和注意事项。 ... [详细]
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • web.py开发web 第八章 Formalchemy 服务端验证方法
    本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
  • Linux的uucico命令使用方法及工作模式介绍
    本文介绍了Linux的uucico命令的使用方法和工作模式,包括主动模式和附属模式。uucico是用来处理uucp或uux送到队列的文件传输工具,具有操作简单快捷、实用性强的特点。文章还介绍了uucico命令的参数及其说明,包括-c或--quiet、-C或--ifwork、-D或--nodetach、-e或--loop、-f或--force、-i或--stdin、-I--config、-l或--prompt等。通过本文的学习,读者可以更好地掌握Linux的uucico命令的使用方法。 ... [详细]
  • 本文介绍了一个React Native新手在尝试将数据发布到服务器时遇到的问题,以及他的React Native代码和服务器端代码。他使用fetch方法将数据发送到服务器,但无法在服务器端读取/获取发布的数据。 ... [详细]
author-avatar
xin新的
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有