-3

我在这里阅读了有关静态与实例方法的信息,但我没有看到任何回答这个特定问题的方法(可能是绿色的)。

当您有一个具有某些属性的类,以及该类中需要使用这些属性的方法时,使用静态方法还是实例方法更好?

IE

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 都不为空,这会导致异常:

Foo foo1 = new Foo();
foo1.bar1 = x;
foo1.bar2 = y;
sumbar1andbar2();

但是,如果该方法修改了该类的另一个属性,例如 bar3,则该实例方法似乎会更好。

4

3 回答 3

2

如果该方法的行为对于 Foo 类型是唯一的(并且在其他地方没有意义地适用),或者如果它修改了 Foo 的状态,那么您可能应该将其设为 Foo 的实例方法。

如果它是一个通用计算(如您的示例),您可能想在其他地方使用它,您有几个选择:

使其成为实用程序类的静态方法,例如

public static class MyUtility {
    public static Int32 Add(Int32 x, Int32 y) { return x + y; }
}

使其成为 Foo 上的扩展方法、父类或定义 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; }
}
于 2012-01-11T23:48:42.273 回答
2

如果它与特定实例相关,那么它必须是实例成员(无论是方法、属性还是字段)。这些是最常见的情况,因此示例很多。

如果它与特定实例无关,则实例成员需要一个您不会以任何其他方式使用的实例。一个很好的例子是Math.Max,如果你调用Math.Max(43, 23)then 结果与 43 大于 23 的事实有关,而不是与Math在应用程序运行过程中可能发生变化的对象的任何属性有关。

有些类只需要静态成员,所以我们将类本身设为静态,根本无法实例化。

出于同样的原因,与类的性质而不是给定实例相关的属性也应该是静态的。egint.MaxValue是 的属性int,而不是 93 的属性。

请注意, 的结果int.MaxValue本身就是一个int. 这并不少见。其他示例包括TimeSpan.Zerostring.Empty。这可能是一种方便,有时也可以在防止大量重复引用类型方面提高性能(与值类型无关,在引用类型的情况下不要夸大其词)。重要的是不要过度这样做。我们不希望 4294967296 个不同的静态属性int让调用它们变得“容易”!通常,这在以下情况下很有用:

特殊情况不能由构造函数构造。

或者:

特殊情况常用 ( TimeSpan.Zero) 和/或不方便记忆(int.MaxValue2147483647甚至更清晰、更容易记忆0x7FFFFFFF)。当然,如果两者兼而有之,那就更是如此。

扩展方法是静态方法,可以像实例成员一样调用。它们非常方便,但通常最好尽可能使用实例成员。当实例成员不可能时,它们很有用,因为:

  1. 您无权访问课程的来源(这是另一方的课程)。
  2. 您想在接口而不是类上定义它。
  3. 您希望它可以在 null 上调用(避免,这在 C# 中是非惯用的,但在其他语言中更常见)。
  4. 您想为泛型的特定情况定义它。例如,如果我创建了MyDictionary<TKey, TValue>该实现IDictionary<TKey, TValue>,则无法定义plus将数字添加到存储值的方法,因为这仅在 TValue 是已知数字类型时才有效。我可以将这样的方法定义为扩展方法int Plus<TKey>(this MyDictionary<TKey, int> dict, int addend),当它是 int 时,它会像实例成员一样出现TValue,但不会干扰MyDictionary其他类型参数的使用。

所有这些情况都让您别无选择,只能使用扩展方法,但不要在实例成员完成工作时使用它们。它更清楚,特别是因为其他一些 .NET 语言只会将扩展成员视为静态成员。

于 2012-01-12T00:08:42.717 回答
1

首先,有一种很好且简单的方法可以确保您的属性不为空:它称为封装。确保在构造函数中设置属性,如果您选择公开属性,请在其设置器中进行验证。这样,在构造对象后属性将非空(否则,构造函数将抛出异常),并且属性设置器将使属性值保持一致状态(否则,设置器将抛出异常)。

现在回到实际问题:如果一个或两个值可能来自的其他实例Foo,请将计算方法设为静态。否则,将其设为实例方法。

PS 如果你的方法返回一个值,没有参数,并且不会产生副作用,请考虑将其作为计算属性而不是方法。

于 2012-01-11T23:50:35.283 回答