【问题标题】:Class<T> and static Class, Best Practices?Class<T> 和静态类,最佳实践?
【发布时间】:2016-09-01 13:49:06
【问题描述】:

我有一个场景(简化)如下:

public static class Example
{
    public const int CONSTANT_VALUE = 1;

    public static Example<T> Create<T>(IEnumerable<T> argument)
        where T : class
    {
        return new Example<T>(argument);
    }

    //More overloads of Create<T>, possibly other static methods, etc..
}

public class Example<T>
    where T : class
{
    public Example(IEnumerable<T> argument)
    {
        //Do Stuff

        //Nothing like this in the real code, just example
        //that constants are used from the other class.
        if (something == Example.CONSTANT_VALUE)             
        {
            //Do A Thing
        }
    }

    //Lots more code
}

基本思想是我可以通过静态类通过类名获得静态方法、常量等,而实际实现在类型参数的非静态类中。

我的问题是这是否是一个很好的设置方法。有没有办法在Example&lt;T&gt; 上放置一些不关心类型参数的静态方法和常量?还有其他更推荐的模式吗?我的工作正常,但我想知道是否还有其他方法,因为这是我第一次最终做这样的事情(并不是说它在概念上对我来说是新的,只是从来没有需要)。

【问题讨论】:

  • 那么,您的类型参数是否适用于整个类(即所有方法),还是仅适用于一种方法有意义?
  • 它适用于整个类,因为该类的主要目的(在我的例子中)是封装一个集合并提供使用它及其内容的方法(主要是返回 T 以供实际使用参数)。在实际代码中,我的类派生自 CollectionView 并实现 ICollectionView,静态类将传入的数据转换为对类型参数类的输入友好的格式,其中有一个常量,并且可能会使用更多静态变量/方法进行扩展根据需要。
  • Tuple 也是如此:Tuple.Create(123, 456) 返回一个Tuple&lt;int, int&gt;。 :)
  • @Caramiriel - 是的,我认为微软有同样模式的例子,我想这至少在某些情况下证实了它是一个有效的模式。供其他人参考,这里是 Tuple 的参考来源,确实是相同的模式:referencesource.microsoft.com/#mscorlib/system/tuple.cs

标签: c# design-patterns static constants generic-type-argument


【解决方案1】:

这只有在常量是公开的情况下才有意义。如果它们仅供Example&lt;T&gt; 内部使用,那么这是没有意义的,因为您可以在没有完全限定名称的情况下引用它们。

如果常量是公共使用的,我也不会使用这种模式; ExampleExample&lt;T&gt; 是两个不同的类,任何用户都可能会感到困惑,而且不是很明显,非泛型类中定义的常量适用于泛型类。

您只是在避免用户敲击几次按键,我不确定这是否值得。

更新:其他选项

在这种情况下,我将使用以下工厂模式(假设用户在您的程序集之外)

public class Example<T>
{
     internal Example() { } //disallow users from instantiating this class
      ...
}

public static class Example
{
    public const int Constant = ...
    public static Example<T> Create<T>() { return new ... }
}

现在所有用户将只与Example 交互,并避免使用Example&lt;T&gt;。您甚至可以对您自己的程序集的用户强制执行此操作,您只需要将 Example&lt;T&gt; 设为实现公共接口的私有嵌套类:

 public interface IExample<T>
 {
     ...
 }

 public static class Example
 {
     private class Example<T>: IExample<T> { ... }
     public static IExample<T> Create<T>() { ... }
     ....
  }

【讨论】:

  • 该常量由ExampleExample&lt;T&gt; 使用,在它们之间共享。我明白你说它可能会使用户感到困惑的意思,但它可以很容易地被称为在不改变模式的情况下使其更清晰的东西,所以我认为这不会影响使用所述模式的决定。
  • 我喜欢这个(第二个选项,带有公共接口)——非常喜欢——我已经以这种方式实现了它,并选择它作为答案。作为记录,我最初实现的模式是完全有效的,但只有在 Example 也需要可访问时才需要 - 这更整洁且更自记录,这足以在以下情况下切换到它您正在尝试编写文档齐全且易于理解的代码(我正在努力做到这一点)。
【解决方案2】:

除非有原因在您的情况下不起作用,否则我宁愿使用非静态基类Example,然后让Example&lt;T&gt; 从此类继承。这样您就可以直接访问Example 中的所有方法,而无需使用名称进行限定。当然,这假设 Example 类专门用于与各种类型的类 Example&lt;T&gt; 结合使用。

【讨论】:

  • 在我的情况下它不起作用,因为 Example 已经从一个基类(我无法控制)继承,所以它不能从另一个继承。不过,对于并非如此的情况,这是一个不错的选择。
  • 这并不意味着它不起作用 - 除非其他基类也是通用的,否则您可以让无类型的 Example 类从该基类继承。
  • 我认为你是对的,是的。顺便说一句,我没有对你投反对票 - 其他人投了票。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-02-28
  • 2011-05-17
  • 1970-01-01
  • 1970-01-01
  • 2011-04-06
  • 1970-01-01
  • 2015-10-03
相关资源
最近更新 更多