我在这里读过关于静态与实例方法的内容,但我没有看到任何回答这个特定问题的答案(绿色可能)。
当你有一个具有某些属性的类,以及该类中需要使用这些属性的方法时,使用静态方法还是实例方法更好?
即
class Foo
{
//properties
bar1;
bar2;
//method
sumbar1andbar2()
{
return bar1 + bar2;
}
}
sumbar1andbar2方法需要存在Foo类的两个属性。制作静态方法并以这种方式调用它似乎有点傻,因为我手动将类的成员传递给类的方法:
Foo foo1 = new Foo();
foo1.bar1 = x;
foo1.bar2 = y;
sumbar1andbar2(foo1.bar1, foo1.bar2);
但是虽然下面的实例方法看起来更清晰,但我不知道一种干净简单的方法来确保bar1和bar2都不为null,这会导致异常:
Foo foo1 = new Foo();
foo1.bar1 = x;
foo1.bar2 = y;
sumbar1andbar2();
但是,如果方法修改了类的另一个属性,例如bar3,则实例方法似乎更好。
答案 0 :(得分:2)
如果方法的行为对于Foo类型是唯一的(并且没有在其他地方有意义地应用),或者如果它修改了Foo的状态,那么你应该把它作为Foo的实例方法。
如果它是一个通用的计算(如你的例子),你可能想在别处使用它,你有几个选择:
使其成为实用程序类的静态方法,例如
public static class MyUtility {
public static Int32 Add(Int32 x, Int32 y) { return x + y; }
}
在Foo上创建extension method,它是父类,或者是定义x和y的接口,例如。
// Use as follows:
// var f = new Foo() { x = 5, y = 5 };
// var ten = f.MyUtility();
public static class MyUtility {
public static Int32 Add(this Foo foo) { return Foo.x + Foo.y; }
}
答案 1 :(得分:2)
如果它与特定实例有关,那么它必须是实例成员(无论是方法,属性还是字段)。这些是最常见的情况,所以例子很丰富。
如果它与特定实例无关,那么实例成员需要一个您不会以任何其他方式使用的实例。一个很好的例子是Math.Max
,如果你调用Math.Max(43, 23)
,那么结果与43大于23的事实相关,而不是Math
对象的任何属性,可以想象地改变应用程序运行的过程。
有些类只需要静态成员,因此我们将类本身设为静态,并且根本无法实例化。
由于同样的原因,与类的性质而不是给定实例相关的属性也应该是静态的。例如。 int.MaxValue
是int
的属性,而非int.MaxValue
。 93。
请注意,int
的结果本身就是TimeSpan.Zero
。这并不罕见。其他示例包括string.Empty
和int
。这可以是一种方便,有时也可以防止大量重复引用类型的性能优势(在值类型的情况下不相关,在引用类型的情况下不会过度说明)。重要的是不要过度这样做。我们不希望在TimeSpan.Zero
上使用4294967296不同的静态属性来让它们“轻松”调用它们!通常,这在以下情况下很有用:
特殊情况不能由构造函数构造。
OR:
特殊情况常用(int.MaxValue
)和/或不方便记住(2147483647
比0x7FFFFFFF
甚至MyDictionary<TKey, TValue>
更清晰,更易于回忆。如果两者都是如此,那就更是如此。
扩展方法是静态方法,可以像实例成员一样调用它们。它们非常方便,但通常情况下最好使用实例成员。当实例成员不可能时,它们很有用,因为:
IDictionary<TKey, TValue>
的{{1}}我无法定义一个plus
方法,该方法会将一个数字添加到存储值,因为这只能在TValue是已知数字类型时才能使用。我可以将这样的方法定义为类似int Plus<TKey>(this MyDictionary<TKey, int> dict, int addend)
的扩展方法,当TValue
为int时,它将显示为实例成员,但不会干扰MyDictionary
对其他类型的使用参数。所有这些情况都让您别无选择,只能使用扩展方法,但在实例成员执行此任务时不要使用它们。它更清楚,特别是因为其他一些.NET语言只会将扩展成员看作静态。
答案 2 :(得分:1)
首先,有一种很简单的方法可以确保您的属性不为null:它被称为封装。确保在构造函数中设置属性,如果选择公开属性,则在其setter中进行验证。这样,在构造对象之后属性将为非null(否则,构造函数将抛出异常),并且属性setter将使属性值保持一致状态(否则,setter将抛出异常)。
现在回答实际问题:如果其中一个或两个值可能来自Foo
的其他实例,请使计算方法保持静态。否则,将其设为实例方法。
P.S。如果您的方法返回一个值,没有参数,并且不产生副作用,请考虑将其设置为计算属性而不是方法。