Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在面向对象方法中使用静态属性或方法有什么不便之处?_C#_Oop - Fatal编程技术网

C# 在面向对象方法中使用静态属性或方法有什么不便之处?

C# 在面向对象方法中使用静态属性或方法有什么不便之处?,c#,oop,C#,Oop,我需要解释我自己为什么不使用静态方法/属性。比如说, String s=String.Empty; 此属性(属于.Net framework)是否错误?应该是什么样子 String s= new EmptySting(); 或 我认为使用静态最糟糕的事情是,最终可能会导致类之间的紧密耦合。在System.Web.Abstracts出现之前查看ASP.NET。这使得类更难测试,并且可能更容易出现导致系统范围问题的bug。为什么每次要使用空字符串时都要创建一个新对象?基本上,空字符串是一个单例对

我需要解释我自己为什么不使用静态方法/属性。比如说,

String s=String.Empty;
此属性(属于.Net framework)是否错误?应该是什么样子

String s= new EmptySting();


我认为使用静态最糟糕的事情是,最终可能会导致类之间的紧密耦合。在System.Web.Abstracts出现之前查看ASP.NET。这使得类更难测试,并且可能更容易出现导致系统范围问题的bug。

为什么每次要使用空字符串时都要创建一个新对象?基本上,空字符串是一个单例对象

正如威尔所说,当涉及到测试时,静态肯定是有问题的,但这并不意味着您应该在任何地方使用静态


(就我个人而言,我更喜欢使用“”,而不是
string.Empty
,但这是一个在其他地方已经讨论到了极点的讨论。)

一般来说,创建一个新的空字符串是一个坏主意-这会在堆上创建额外的对象,因此垃圾收集器需要额外的工作。当需要空字符串时,应始终使用String.Empty或“”,因为它们是对现有对象的引用。

三个不同示例的语义非常不同。我会试着在实践中把它分解


这是一个单身汉。当你想确保某件事中只有一件时,你可以使用它。在这种情况下,因为字符串是不可变的,所以只需要一个“空”字符串。不要过度使用单例,因为它们很难测试。但是,当它们有意义时,它们是非常强大的


这是您的标准构造函数。你应该尽可能使用这个。只有当单例的情况非常严重时,才重构为单例模式。对于
string.Empty
,使用单例非常有意义,因为不能通过引用类来更改字符串的状态


实例工厂和静态工厂,比如单例,应该少用。在大多数情况下,当类的构造很复杂并且依赖于多个步骤,并且可能依赖于状态时,应该使用它们


如果对象的构造依赖于调用方可能不知道的状态,那么应该使用实例工厂(如示例中所示)。当构造很复杂,但调用方知道会影响构造的条件时,应该使用静态工厂(例如
StringFactory.CreateEmpty()
StringFactory.Create(“foo”)
。但是,对于字符串来说,构造非常简单,使用工厂就好像是在寻找问题的解决方案。

对于
string.Empty
来说,它更像是一个常量(有点像
Math.PI
Math.E
)并为该类型定义。为一个特定值创建子类通常是不好的

关于你的另一个(主要)问题,关于他们如何“不方便”:

我只发现静态属性和方法在被滥用以创建更具功能性的解决方案,而不是C#所指的面向对象方法时会带来不便

我的大多数静态成员要么是上述常量,要么是类似工厂的方法(如
Int.TryParse

如果类有很多静态属性或方法用于定义由类表示的“对象”,我会说这通常是糟糕的设计

静态方法/属性确实让我感到困扰的一个主要问题是,有时它们太依赖于一种方法,而没有提供一种简单的方法来创建一个实例,该实例提供了对行为的简单覆盖。例如,假设您希望以度而不是弧度进行数学计算。由于
Math
都是静态的,因此您不能这样做,而是每次都必须转换。如果
Math
是基于实例的,您可以创建一个新的
Math
对象,该对象默认为弧度或度数,并且仍然可以具有典型行为的静态属性

例如,我希望我可以这样说:

Math mD = new Math(AngleMode.Degrees); // ooooh, use one with degrees instead
double x = mD.Sin(angleInDegrees);
但我必须写下这句话:

double x = Math.Sin(angleInDegrees * Math.PI / 180);
(当然,您可以为转换编写扩展方法和常量,但您明白我的意思)

这可能不是最好的例子,但我希望它传达了一个问题,即不能使用默认方法的变体。它创建了一个函数构造,并与通常的面向对象方法相违背


(作为旁注,在本例中,每个模式都有一个静态属性。在我看来,这是对静态属性的合理使用)。

一般来说,静态的目的是确保程序中只有一个静态“东西”的实例

  • 静态字段在类型的所有实例中保持相同的值
  • 静态方法和属性不需要实例才能被调用
  • 静态类型只能包含静态方法/属性/字段
当您知道您正在创建的“东西”在程序的生命周期内永远不会更改时,静态非常有用。在您的示例中,
System.String
定义了一个私有静态字段来存储空字符串,该字段只分配一次,并通过静态属性公开

如前所述,静态存在可测试性问题。例如,很难模拟静态类型,因为它们无法实例化或派生。也很难将模拟引入某些静态方法,因为它们使用的字段也必须是静态的。(您可以使用静态setter属性来解决这个问题,但我个人尝试避免这种情况,因为它通常会破坏封装)

在大多数情况下,使用静态是可以的。您需要决定何时在使用静态实体和基于实例的实体之间进行权衡
String s= new EmptySting();
IEmptyStringFactory factory=new EmptyStringFactory();
String s= factory.Create();
Math mD = new Math(AngleMode.Degrees); // ooooh, use one with degrees instead
double x = mD.Sin(angleInDegrees);
double x = Math.Sin(angleInDegrees * Math.PI / 180);