【问题标题】:Is there a way to force a C# class to implement certain static functions?有没有办法强制 C# 类实现某些静态函数?
【发布时间】:2010-10-09 07:55:28
【问题描述】:

我正在开发一组实现通用接口的类。我的库的使用者应该期望这些类中的每一个都实现一组特定的静态函数。无论如何我可以装饰这些类,以便编译器能够捕获其中一个函数未实现的情况。

我知道它最终会在构建消费代码时被捕获。而且我也知道如何使用一种工厂类来解决这个问题。

只是想知道是否有任何语法/属性需要类上的静态函数。

Ed删除了“界面”一词以避免混淆。

【问题讨论】:

  • 请原谅我的好奇心,但我不禁想知道你为什么需要这样的功能?静态方法有什么普通实例(非静态)方法没有的?我什么都没有想到。想为您的问题分享一些背景信息吗?
  • 您不需要实例来调用静态方法。所以它们很适合用作工厂方法,例如反序列化方法。
  • @Dan:另一个用途是在不知道您是在处理实例还是类型(或稍后更改)的情况下使用接口的能力。考虑一个代表某种单例列表的静态类——作为一个适当的列表,它应该实现IList<T>。当然,在静态类中存储实现 IList<T> 的类的实例的解决方法是可行的(我知道 C# 目前只允许这种方式),但是直接将类声明为静态实现的能力接口会删除不必要的间接级别。

标签: c# .net interface static-methods


【解决方案1】:

不,C# 中没有对此的语言支持。我可以立即想到两种解决方法:

  • 在运行时使用反射;交叉手指和希望......
  • 使用单例/默认实例/类似来实现声明方法的接口

更新

实际上,只要您进行单元测试,如果(像我一样)您来自严格的“静态类型”背景,第一个选项实际上并没有您想象的那么糟糕。事实上;它在动态语言中运行良好。事实上,这正是我的generic operators 代码的工作原理——希望你有静态运算符。在运行时,如果你不这样做,它会以适当的嘲弄语气嘲笑你……但它无法在编译时检查。

【讨论】:

  • 如果代码以适当的嘲弄语气嘲笑我,我会很高兴的。等等,这种事总会发生。没关系。 ;-)
【解决方案2】:

没有。基本上听起来你在追求一种“静态多态性”。这在 C# 中不存在,尽管我建议使用 "static interface" notion which could be useful in terms of generics

可以做的一件事是编写一个简单的单元测试来验证特定程序集中的所有类型是否符合您的规则。如果其他开发人员也将实现该接口,您可以将该测试代码放在某个公共位置,以便实现该接口的每个人都可以轻松地测试他们自己的程序集。

【讨论】:

  • 可以在接口契约中指定接口的所有合法实现必须具有某些静态成员并且,如果未密封,则包含在它们的继承中合同要求所有合法派生类型必须遵守相同的要求。这不会阻止人们编写接口的非法实现,但情况不会比使用几乎任何其他类型的接口更糟。
  • @supercat:“合同”是指“文档”还是代码合同之类的东西?
  • 我的意思是文档。任何有意义的接口都必须有一组要求,满足这些要求的实现是合法的,不满足这些要求的实现是非法的。没有必须表达此类要求的固定格式,但如果例如IList<T> 的实现有一个属性设置器,它忽略了 index 参数并简单地覆盖了一个随机元素,许多期望使用 IList<T> 的方法会失败,不是因为方法有缺陷,而是因为 @987654325 @ 实现是非法的。
  • @supercat:是的,完全可以忽略需求——但我仍然欢迎编译器为我找到最简单违规行为,所以我认为我不会同意它“不会比使用几乎任何其他类型的界面更糟糕”。
  • 拥有一个空的标记接口,其契约规定它只能由满足上述要求的类实现,不会在类实现接口中发现违规,但会如果代码试图将不合适的类型传递给必须调用相关静态方法的方法,则在 client 端捕获违规。我认为这足以证明拥有标记界面是正确的。
【解决方案3】:

这是一个很好的问题,也是我在项目中遇到的一个问题。

有些人认为接口和抽象类的存在只是为了多态性,而不是为了强制类型实现某些方法。就个人而言,我认为多态性是主要用例,而强制实现是次要用例。我确实经常使用强制实现技术。通常,它出现在实现模板模式的框架代码中。基类/模板类封装了一些复杂的想法,子类通过实现抽象方法提供了许多变体。一个实用的好处是抽象方法为实现子类的其他开发人员提供了指导。 Visual Studio 甚至可以为您存根方法。当维护开发人员需要在数月或数年后添加新的子类时,这尤其有用。

缺点是在 C# 中没有对其中一些模板方案的特定支持。静态方法就是其中之一。另一种是构造函数;理想情况下,ISerializable 应该强制开发人员实现受保护的序列化构造函数。

最简单的方法可能是(如前所述)使用自动化测试来检查静态方法是否在所需类型上实现。已经提到的另一个可行的想法是实现静态分析规则。

第三种选择是使用面向方面的编程框架,例如PostSharp。 PostSharp 支持方面的编译时验证。您可以编写在编译时反映程序集的 .NET 代码,从而生成任意警告和错误。通常,您这样做是为了验证方面的使用是否合适,但我不明白为什么您也不能使用它来验证模板规则。

【讨论】:

    【解决方案4】:

    很遗憾,没有,语言中没有这样的内容。

    【讨论】:

      【解决方案5】:

      虽然没有对此的语言支持,但您可以使用静态分析工具来强制执行它。例如,您可以为 FxCop 编写自定义规则,检测类的属性或接口实现,然后检查某些静态方法是否存在。

      【讨论】:

        【解决方案6】:

        单例模式并非在所有情况下都有帮助。我的例子来自我的一个实际项目。这不是人为的。

        我有一个继承自第三方 ORM 中的类的类(我们称之为“Widget”)。如果我实例化一个 Widget 对象(因此在 db 中创建一行)只是为了确保声明了我的静态方法,那么我会造成比我试图清理的更大的混乱。

        如果我在数据存储中创建这个额外的对象,我必须对用户、计算等隐藏它。

        我在 C# 中使用接口来确保在一组类中实现通用功能。

        实现这些功能的一些方法需要实例数据才能运行。我将这些方法编码为实例方法,并使用 C# 接口确保它们存在于类中。

        其中一些方法不需要实例数据,因此它们是静态方法。如果我可以用静态方法声明接口,编译器可以检查这些方法是否存在于说它实现了接口的类中。

        【讨论】:

          【解决方案7】:

          不,这个功能没有意义。接口基本上是多重继承的缩小形式。它们告诉编译器如何设置虚函数表,以便可以在后代类中正确调用非静态虚方法。静态方法不能是虚拟的,因此,为它们使用接口是没有意义的。

          【讨论】:

          • 这里面肯定有的一点——仅仅因为不会通过接口调用方法并不意味着不值得测试它们的存在。这有点像 C# 公开的 new T() 约束 - new T() 的实际实现有效地通过反射......
          • 我不希望它们是虚拟的,只是强制它们存在。
          • 我支持 dsimcha。如果显式声明接口的目的不是将接口与实现分开,那么剩下的“接口”就不多了。如果您需要某些类具有某些方法,则可以发明一些其他语言元素,例如 HasToImplementMethodsAttrib
          • 将“界面”排除在外,它只是提供了一些上下文。
          【解决方案8】:

          正如 Marc Gravell 所建议的,让您更接近所需的方法是单例。

          接口让您可以为类提供某种程度的抽象,这样您就可以使用给定的 API,而不管实现它的类型如何。但是,既然您确实需要知道静态类的类型才能使用它,那么为什么要强制该类实现一组函数呢?

          也许您可以使用 [ImplementsXXXInterface] 之类的自定义属性并提供一些运行时检查以确保具有此属性的类实际实现了您需要的接口?

          【讨论】:

          • 运行时检查不好,因为编译器在构建消费者代码时已经选择了它。只是想知道我是否可以让编译器更早地接收它。
          【解决方案9】:

          如果您刚刚遇到这些编译器错误,请考虑以下设置:

          1. 在接口中定义方法。
          2. 用抽象声明方法。
          3. 实现公共静态方法,并让抽象方法重写简单地调用静态方法。

          这是一些额外的代码,但是当有人没有实现所需的方法时,您会知道。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-02-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-04-21
            • 2022-01-05
            • 1970-01-01
            相关资源
            最近更新 更多