c# - 使用静态只读与静态 getter 模拟常量

标签 c#

我正在使用第三方控件,该控件使用“奇怪的值”来区分选项列表。他们使用两个不同的属性来唯一地标识每个选择。

Example:
"Field" + "RW" = "CheckedOutBy"
"System" + "N" = "Name"
"Field + "N" = "Notifier"

总共有 37 种不同的选择(每种选择都有两个值的不同组合,以构成 37 种独特的选择)。

我创建了一个存储这两个值的结构,我的想法是为每个选择创建一个新的结构实例。

public struct ColumnCode : IEquatable<ColumnCode>
{
    public static readonly ColumnCode Empty = new ColumnCode();

    private readonly ColumnType _columnType;
    private readonly string _code;

    internal ColumnCode(ColumnType columnType, string code)
    {
        _columnType = columnType;
        _code = code;
    }

    public override string ToString() { ... }
    public bool Equals(ColumnCode other) { ... }
    public override int GetHashCode() { ... }
}

理想情况下,我想为每个选择创建一个“常量”,但由于常量不是一个选项,我想尝试模仿常量。

我提出的两种方法是使用静态只读字段或仅使用 getter 的静态属性。

public static class FieldOption 
{
    public static ColumnCode CheckedOutBy { get; } = new ColumnCode(ColumnType.Field, "XW");
    public static ColumnCode Name { get; } = new ColumnCode(ColumnType.System, "N");
    public static ColumnCode Notifier { get; } = new ColumnCode(ColumnType.Field, "N");
}

public static class FieldOption 
{
    public static readonly ColumnCode CheckedOutBy = new ColumnCode(ColumnType.Field, "XW");
    public static readonly ColumnCode Name= new ColumnCode(ColumnType.System, "N");
    public static readonly ColumnCode Notifier = new ColumnCode(ColumnType.Field, "N");
}

无论哪种情况,我现在都可以使用 FieldOption.CheckedOutByFieldOption.NameFieldOption.Notifier 引用 C# 代码中的选择等等,但我不确定一种方法是否比另一种更好。

这些选择中的一个比另一个更好地模仿 const,还是有我没有考虑的更好方法。

我在互联网上阅读了大量信息,但仍然没有想出一个好的答案。其中有些似乎是矛盾的。许多信息都指出属性优于字段,但在本文 ( https://msdn.microsoft.com/en-us/library/ms229057(v=vs.110).aspx ) 中,微软表示“请对预定义对象实例使用公共(public)静态只读字段”,所以我觉得静态只读字段是正确的选择。

我也不确定反射在这里如何发挥作用。我想确保 FieldOptions 的值不能更改,即使通过反射也是如此。

对此的任何帮助将不胜感激。

最佳答案

I want to make sure that the values for the FieldOptions cannot be changed, even through reflection

实现这一点的唯一方法是使用只读属性,即使这样,也只有在每次调用 getter 时重新实例化相应的值,例如:

public static ColumnCode CheckedOutBy
{
    get { return new ColumnCode(ColumnType.Field, "RW"); }
}

使用您显示的语法或带有私有(private) setter 的自动属性,仍然有一个支持字段,并且该支持字段仍然可以通过反射进行更改,尽管稍微困难一些,因为字段名称在源代码并具有依赖于编译器实现的名称。

当然,每次调用 getter 时重新实例化该值会对性能产生负面影响。因此,将属性设置为深度只读(即不受反射影响)是有代价的。您必须自己确定此性能成本在您的场景中是否重要。这个问题没有“唯一正确答案”。

I have read a large amount of information on the internet and am still not coming up with a good answer. Some of it seems to be conflicting

这是因为,除了您有一些特定约束来影响您的决定的情况(例如想要防止反射能够更改值)之外,这实际上主要是个人偏好的问题。 The previously proposed duplicate answer解决了许多区分字段和属性的问题,但作为您所询问的特定场景中的实际问题,几乎没有什么真正的区别。

字段名义上性能更好,因为可以直接访问它们而不需要方法调用。但是 a) 在许多情况下,方法的主体将被内联,从而抵消了这一优势,并且 b) 即使方法调用存在,在大多数情况下,它也没有足够的开销来影响甚至是可测量的。


因此,您需要决定:您有多需要保护以防止代码通过反射修改这些值?它真的足够重要以至于值得用程序生成的值将值包装在属性中吗?如果您这样做,您将多久访问一次这些属性?每次调用 getter 时按需生成值的开销是否足够频繁,从而影响代码的实用性?

这些问题只有您才能回答。这里的人不可能为您回答这个问题。

关于c# - 使用静态只读与静态 getter 模拟常量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37955469/

相关文章:

c# - 使用 Linq 执行 SQL 函数

c# - 如何在类中动态创建属性

c# - TCPClient - 一段时间后停止接收数据

c# - 如何通过SessionId获取Session对象?

c# - MVC 构建电子邮件正文

javascript - 如果选择了其中之一,则禁用 Asp.net RadioButtonList 中的其他 RadioButton

c# - 错误 SIPEPS,版本 = 5.0.0.0 UCMA 4.0 VS2010/VS2013

c# - Visual Studio 对我来说已经崩溃了?

c# - Linq 查询包含对象列表的对象列表

c# - 每个项目 C# 的 log4net 配置