【问题标题】:Why include static members within a primarily non-static class?为什么在主要是非静态类中包含静态成员?
【发布时间】:2014-07-18 20:48:30
【问题描述】:

我无法理解在通常充当实例化蓝图的类中包含静态成员的总体原则是什么。我举个例子:

假设你有 Car 课程。

Class Car
{
  public int yearBuilt;
  public string make;
  //etc
}

主要用于生产新车。所以你有一堆非静态成员,如预期和上面所示。现在,假设您按如下方式实例化 2 辆新车

Car.newCar1 = new Car();
Car.newCar2 = new Car();

现在,假设您想为今天制造的新车分配/跟踪供应商。假设您在任何时候只能有一个供应商,您认为此时制造的所有 newCar 都应该共享该值,因此您添加到 Car 类:

public static string supplier = "American AutoCompany X";

我现在无法通过实例访问它,即:newCar1.supplier,否则它会更改 newCar2 的值(在这种情况下是可以且更可取的),而是必须这样做才能完成相同的操作目标:

Car.supplier;

我不明白这一点。为什么不把你的静态方法/字段等放在一个完全不同的类中,比如:

class AllStaticStuff
{
}

并从那里访问它?从组织上讲,这甚至可能更可取,因为静态成员无论如何都与实例化无关。还是我错过了一些基本的东西,使这种组织方法比它的价值更麻烦?我想我不喜欢在非静态类中包含静态的想法的原因是我试图避免在任何一个类中不必要地增加成员,因为为了可读性,我觉得它更干净。

【问题讨论】:

  • 在这种情况下,供应商应该属于Car 实例,而不是Car 类本身。静态属性、字段和方法不应特定于实例,而应特定于整个类。
  • Anthony:我知道你的意思,但是,在不阅读所用术语的含义的情况下,让我们假设“供应商”确实是属于整个班级的东西。实际上,这就是我想要传达的情景。
  • @StevenNikolic 然后选择一个不同的例子。很明显,每辆车可以有不同的供应商,因此静态在这种情况下不合适。
  • mason:我不太明白你为什么这么说。静态描述了它是跨类成员的共享状态/值/进程这一事实,而不是它不会改变。或者,我又错过了什么?

标签: c# static encapsulation


【解决方案1】:

实际上,这仅取决于您尝试使用代码创建的抽象。

如果您使用希望在另一个类的所有实例之间共享的数据创建一个类,则无论如何您都必须将该类设为静态。有时创建一个静态成员会更简洁。

我认为您的汽车示例不是一个很好的示例,因为汽车拥有 Supplier 属性是没有意义的,除非供应商可以在实例之间变化。

我认为,一个更好的例子是保留一个持有计数器的静态成员。想象一下,如果您正在跟踪您打开了多少个类的实例。每次创建实例时,计数器都会递增。类的所有实例都需要知道这个数字。它只与这个类有关,那么为什么要为计数器数据创建一个单独的类呢?

Car.Counter 在逻辑上对人类来说比 AllStaticStuff.Counter 更有意义。比较明显。

【讨论】:

  • 你的意思是把静态计数器放在构造函数中,等等?当然,我能理解你为什么要这么做。好的,对于您想要跟踪每个实例化发生的更改的特定场景,这当然是一个很好的案例。然而,我详述的场景不会随着每次实例化而改变。
  • 我不确定你的最后一句话是什么意思。在您的场景中,您是说该类的所有实例都将具有等于特定字符串的数据成员。在这种情况下,为什么不直接使用常量呢?我觉得你的例子有点破坏你的问题。当然,在某些情况下,您可能希望将所有常量放在一个单独的类中,但这取决于您更清楚、更容易理解的内容。
  • 我的示例很可能会破坏我的意图,我的意图不是让这个特定示例启动并运行,而是更深入地了解为什么人们会在通常的非静态中使用静态的原因类作为默认的编码实践。直接响应您声明常量的示例,那么,想法是最终用户可以(有一天)更改“供应商”值,但在任何时候,它的值肯定会在所有新创建的实例之间共享。因此,常数肯定不是解决方案。
  • 在这种情况下,我会使用配置文件并将供应商的类变量设置为其中的任何内容。
  • 关键是这取决于你在做什么。我知道您并不是真的想强调这种特殊情况。除了某种计数器之外,我想不出任何具有更改共享值的示例,这对于静态成员来说是一个很好的用例。如果其他人可以,请随时将其添加到我的答案中。
【解决方案2】:

我喜欢将静态成员视为操作(还有很多其他用途),但假设您拥有汽车对象,但您需要做一些事情,例如抓取汽车的图像(无论年份和制造都无关紧要,它可以找到它),你可以做这样的事情。

Class Car
{
   public int yearBuilt;
   public string make;

   public static string GetImageOfCar(Car c)
   {
     // File operations to find the correct image on the drive and return its path as a string   
     // use c.yearBuilt somewhere 
     // use c.make somewhere
   }
}

然后在类之外,当你实例化一个汽车对象时,你可以这样做:

Car aCar = new Car();
aCar.yearBuild = 1983;
aCar.make = "Ford Truck";

MessageBox.Show(Car.GetImageOfCar(aCar)); // Would return the path to the image

就您的供应商名称而言,我只是创建属于每个对象的另一个字段,因为每辆汽车“技术上”可能有一个单独的供应商。我想你可以制作一个常量或其他东西,但你仍然需要某种字段来轻松识别我认为的每个对象。您可以简单地创建一个静态字段,并在需要时在类外部使用该值。在 Car 类中,您可以输入以下内容:

public static string Supplier = "name of supplier";

然后在课堂外使用:

MessageBox.Show(Car.Supplier);

【讨论】:

  • 不应该是公共静态字符串GetImageOfCar(int yearBuilt, string make)吗?
  • 可以,但我这样做的方式允许您传入一个已经设置了这些值的汽车对象(如果有意义的话)。
  • 但是当您调用该方法时,您假设您为两个参数传递了同一辆车。这没有意义。你打电话给a.yearBuild, a.Make,在这种情况下你应该只传入一个Car。这实际上会使这个静态方法更符合 .NET 库中的许多静态方法,尤其是许多将字符串作为参数的 String 方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-13
  • 1970-01-01
  • 2023-03-06
  • 2011-02-13
  • 2012-01-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多