对于一个字段的简单接口,这些选项之间有什么区别?
本文关键字:之间 选项 什么 区别 字段 于一个 简单 接口 | 更新日期: 2023-09-27 18:13:39
我只是盯着下面的代码,想知道是否真的有必要填满12行源代码。
private static IUnityContainer _container;
public static IUnityContainer Container
{
get
{
return _container;
}
set
{
_container = value;
}
}
我的想法是,为什么不只有一个?
public static IUnityContainer Container;
我认为答案是类似于"你不能打破封装"…这更多的是对条件反射的膝跳反应,还是有其他的原因,微妙的或其他的?
除非您不想以某些奇怪的方式(如GetType())使用反射。GetProperty("Container"…)没有缺点
然而,暴露字段被认为是不干净的,从纯粹主义者的角度来看,属性通常是干净的。
FxCop会警告你这不是一件好事,但也没有缺点。
如果你想同时保持简洁,你可以使用自动属性:
public static IUnityContainer Container { get; set; }
自动属性只在编译器3.0版本起作用。
可能发生的缺点是,如果您或某人在某些函数中通过ref传递该字段,例如Interlocked.Exchange(ref MyClass.MyStaticField, null);
如果将来用属性更改它,它将不再工作,因此您应该小心不要通过引用传递该字段。如果你从一开始就使用一个属性,你就不会有这个问题。static readonly
字段不会出现这个问题,它们不能通过引用传递。使用静态只读字段是很常见的。
当你有一个类继承了用于远程处理(RPC,远程过程调用)的MarshalByRefObject时,绝对不应该使用字段来代替属性。
我在这里发布了一个例子,正如我所说,这不是你的情况,因为问题是与实例字段,而不是与静态字段。
public class MyClass :
MarshalByRefObject
{
public int MyValue;
}
class Program
{
static void Main(string[] args)
{
var obj = new MyClass();
// This will give you warning CS1690: Accessing a member on 'MyValue' may cause a runtime exception because it is a field of a marshal-by-reference class
Console.WriteLine(obj.MyValue.ToString());
}
}
远程过程调用只能与方法和属性一起工作,因此编译器会给你一个警告,因为MarshalByRefObject可以在另一个AppDomain中调用,也可以由另一个进程或另一台计算机通过TCP/IP调用。
我个人是这样认为的。假设在稍后的某个时间,我想建立一个不变式,即"容器"永远不会为空。如果它被定义为公共字段,那么强制执行的方法是找出使用它的每个客户端,并放入代码以防止它被设置为null。如果我把它作为一个属性,同样的事情也可以像这样完成:
private static IUnityContainer _container = new ContainerImpl();
public static IUnityContainer Container
{
get
{
return _container;
}
set
{
_container = value ?? _container;
}
}
或者,您可以对空值抛出异常,以便更有表现力。具体细节并不重要,重要的是封装角度。
所以,我认为这不是一个简单的下意识的反应,而是一个实用和合理的,特别是面对静态关键字。如果没有封装,它实际上只是一个全局变量。至少封装全局状态允许提供者对其进行某种表面上的控制,而不是在整个应用程序中泄漏控制,并信任/强制客户端保持一致。
有人可能会认为这是"不要重复自己"的问题。当涉及到一个字段时,任何公共逻辑都必须在所有地方复制。