8

我最近向我的一位同事提出了一项建议,指出在我们当前的项目 (C#) 中,“服务应该是无状态的,因此是静态的”。

我的同事同意并指出,在我们的项目中,服务是(并且应该是)确实是无国籍的。然而,我的同事不同意静态意味着没有状态,而无状态应该意味着静态。

我的问题是“标记为静态的方法是否意味着它不需要状态,并且在大多数情况下应该将无状态方法设为静态”。

4

13 回答 13

8

静态几乎意味着全局。仍然存在一个实例,并且该实例中仍然存在状态,但它是静态实例,这意味着只有一个实例,并且所有调用者始终引用该实例。

于 2009-10-27T01:10:32.020 回答
5

标记为静态的方法是否意味着它不需要状态

1)不。你不能说静态方法意味着它不需要状态,因为静态方法可以访问静态/单例资源。

大多数情况下应将无状态方法设为静态

2) 是的。不需要状态的方法,因此不需要实例,通常应该是静态的。

于 2009-10-27T01:13:15.537 回答
3

C# 中的静态方法可以访问其包含类的静态变量,如果可以访问,则它不是无状态的。我已经看到了一些触发有趣竞争条件的非重入“无状态”静态方法的痛苦实例。

真正的无状态方法确实可以设为静态,而且通常应该如此。

于 2009-10-27T01:12:31.317 回答
3

我认为他的声明与“民主国家应该使用黄纸选票”一样有道理。

他将高级设计概念“无状态服务”与低级技术实现细节“使用静态类”混合在一起。

无状态服务可以(并且已经)用只支持静态变量的语言(例如 COBOL、RPG)和甚至不允许静态变量的语言(Erlang 等)实现。

我可以很容易地想象一个无状态服务主要使用静态类实现的情况,因为它们在那里并且已经实现了正确的业务逻辑,尽管它通常被认为是良好的 Java 编程实践,除非你真的需要,否则不要使用静态类。

他还严重误解了“静态”的全部含义——静态变量是在调用之间存储状态的一种方式——因此似乎更适合与“有状态”服务相匹配。

于 2009-10-27T01:44:14.600 回答
3

我觉得说无状态与静态相同是相当可怕的,因为这是两个不同的世界。无状态意味着没有状态保持,即一个完美的例子是一个 HTTP 连接(一旦发送数据,连接关闭并且没有任何内存保留),我们实际上试图尽最大努力保持状态,不管(登录状态为一)。

另一方面,静态是用于描述调用方法的方式的术语。在 C# 中,这意味着可以在没有类实例的情况下调用方法,但类的实例与状态不同。仍然有静态实例,它完全能够维护状态:任何静态成员变量、字段或属性都可以维护状态。静态方法或类也完全能够通过使用内存映射文件、数据库或其他东西来维护状态。静态是一种调用约定,仅此而已,与是否无状态无关。

于 2009-10-27T01:17:06.730 回答
2

static是语言关键字,state是设计概念。这两件事之间有明显的关系,但这是具体与形而上学的关系,而不是因果关系。静态方法可以引用某些类型的状态信息。

关于无状态方法,这里我们讨论的是不引用类实例的方法,即 this 指针。将这些方法标记为静态可以提高代码的清晰度,并且符合最佳实践。请注意,在这种情况下,我们谈论的是一种特定的“无状态”,而不是对有状态上下文的使用进行一般性评论。

于 2009-10-27T01:24:41.503 回答
1

除了重新定义人们可以通过的“静态”的所有定义之外,答案是“是的”。静态方法可以愉快地修改类本身的状态(通过静态变量表示),甚至修改类实例的状态(特别是当它们传递一个实例或一组实例时)。但是,大多数情况下,您将在未更改状态的情况下使用静态方法。最重要的示例是查找或创建实例(工厂方法)。

也就是说,真正的答案是“不”。在现实生活中(例如,基于 HTTP 的 Web 服务,或与​​任何类型的 Orb 交互),服务从不使用实际的静态方法公开其服务方法。您通常调用静态方法来获取服务的实例(或服务工厂的实例,从中获取实例!),然后使用它。这是因为您的服务代理在内部需要跟踪它的位置。因此,尽管您的方法对您来说似乎是无状态的,但实际上并非如此。

希望这不会太令人困惑:)

于 2009-10-27T02:03:14.707 回答
1

静态类不是无状态的。它仍然可以有变量,虽然是静态的,但有状态。

没有任何类级变量的静态类是无状态的。它不保存任何数据。

于 2009-10-27T02:03:25.810 回答
1

静态可以是有状态的。您只需要为所述状态定义静态容器。并且容器在对静态方法的所有调用之间共享。

于 2009-10-27T01:14:21.510 回答
1

每个类都有一个类定义结构,其中表示和存储静态字段。类的每个“实例”都可以访问存储在类定义中的静态字段(数据结构 caleld CORINFO_CLASS_STRUCT)。即使没有创建任何实例,程序集中的任何地方的代码都可以使用语法访问这些静态类级字段classname.StaticFieldName,而根本不需要任何实例。

由于存储在这些静态类级字段中的值是持久的,因此它们肯定是状态。事实上,它们不仅由可能存在的类的任何实例共享状态,而且在整个程序集中共享,无论是否创建了任何实例。

更重要的是,由于一旦CORINFO_CLASS_STRUCT加载了类定义,与类的真实实例不同,它在程序集(或 AppDomain)被卸载之前永远不会被卸载,因此它可以说比在类中定义的任何实例字段更有状态,因为当实例被垃圾收集时,实例字段消失。

欲了解更多信息,请查看CORINFO_CLASS_STRUCTDon Boxes 的好书Essential .Net的链接

于 2009-10-27T01:19:43.637 回答
1

对您的问题的简短回答是“否”,static并不意味着“没有状态”。

参考您的其他评论,static可用于帮助您实现无状态服务,但static仅此还不够。另一种帮助实现无状态的工具/技术是使用不可变数据结构。这(当前)不是 C# 的强项之一,尤其是与 F# 相比。

于 2009-10-27T01:49:05.027 回答
0

这通常是正确的。但是你可以有静态变量,它允许你的静态方法有状态。例如,使用这个 FooBarFactory 类:

class FooBarFactory
{
    private static _id = 0;
    public FooBar MakeAFooBar()
    {
        FooBar foo = new FooBar();
        foo.ID = _id;
        _id++;
    }
}
class FooBar
{
    public int ID {get;set;}
}

在这种情况下,您的静态方法具有最少的状态,但它(可能)是必要的。

于 2009-10-27T01:13:40.423 回答
-1

如果您想要一个有状态的实例,请使用单例模式;它清楚地表明您正在使用单次出现的对象。

从那以后,我会将所有静态类和方法视为无状态的。它只是有助于保持理智。

于 2009-10-27T01:16:49.443 回答