在没有反射的情况下设置ReadOnly字符串

时间:2016-07-08 13:50:54

标签: c# reflection readonly

我正在开发一个需要访问公共字符串的应用程序。 但是,我也希望限制写访问权限。由于我有很多字符串,我想避免为每个字符串设置一个getter和private setter。

见下面的代码:

public readonly string privateMem, peakVM, peakPaged, pagedSysMem, pagedMem, nonpagedSysMem;

    public override void Capture()
    {
        using (Process p = Process.GetCurrentProcess())
        {

            // Throws error as privateMem can't be assigned a value

            privateMem = string.Format("{0:N0} K", p.PrivateMemorySize64 / 1024);
            peakVM = string.Format("{0:N0} K", p.PeakVirtualMemorySize64 / 1024);
            peakPaged = string.Format("{0:N0} K", p.PeakPagedMemorySize64 / 1024);
            pagedSysMem = string.Format("{0:N0} K", p.PagedSystemMemorySize64 / 1024);
            pagedMem = string.Format("{0:N0} K", p.PagedMemorySize64 / 1024);
            nonpagedSysMem = string.Format("{0:N0} K", p.NonpagedSystemMemorySize64 / 1024);
        }

    }    

我知道有一些方法可以使用反射为readonly字段赋值,但是我从其他几个stackoverflow问题中收集到了这是一个糟糕的想法。

总之:

1。 如何在没有反射的情况下为只读字符串赋值,或者在不使用详细的getter和setter的情况下是否存在更好的解决方案?

2。 有没有办法声明变量,为它赋值,然后将其指定为只读?

4 个答案:

答案 0 :(得分:7)

你要做的事情毫无意义。只读字段只能填充在构造函数中。它们对于依赖注入非常有用,例如,事物只在构造函数中设置,而且它不能在它之外修改。

您总是可以使用私人套装。说getter和setter是" verbose"没有任何意义。他们是有原因的。试图找到一种以不同方式做事的方法很可能意味着疯狂的代码以及所有这些只是为了避免使用简单的setter?

想想你在做什么以及为什么然后最终问问自己,这真的值得吗?

答案 1 :(得分:0)

我最后只是使用字典。这样我只需要一个getter和private setter,并且它可以在以后添加更多的字符串/系统信息时具有更大的可扩展性。

public Dictionary<string, string> memoryStrings
         {
             get;
             private set;
         }

        public MemoryUsageFragment() {
            memoryStrings = new Dictionary<string, string>();
        }

        public override void Capture()
        {
            using (Process p = Process.GetCurrentProcess())
            {
                memoryStrings.Add("privateMem", string.Format("{0:N0} K", p.PrivateMemorySize64 / 1024));
                memoryStrings.Add("peakVm", string.Format("{0:N0} K", p.PeakVirtualMemorySize64 / 1024));
                memoryStrings.Add("peakPaged", string.Format("{0:N0} K", p.PeakPagedMemorySize64 / 1024));
                memoryStrings.Add("pagedSysMem", string.Format("{0:N0} K", p.PagedSystemMemorySize64 / 1024));
                memoryStrings.Add("pagedMem", string.Format("{0:N0} K", p.PagedMemorySize64 / 1024));
                memoryStrings.Add("nonpagedSysMem", string.Format("{0:N0} K", p.NonpagedSystemMemorySize64 / 1024));
            }    
        }

答案 2 :(得分:0)

您目前使用字典的答案不正确,因为它不是只读的。

更正确的方法是基于字典初始化IReadOnlyDictionary(在.NET 4.5或更高版本中)实例,并添加逻辑以防止在初始化后用新值覆盖它。

通过使用支持字段,我们可以确保即使在类内部发生修改它的尝试,也只有在包含值​​时才能覆盖它。

private IReadOnlyDictionary<string, string> _memoryStrings;
public IReadOnlyDictionary<string, string> memoryStrings
{
    get
    {
        return _memoryStrings;
    }
    private set
    {
        if (_memoryStrings != null && _memoryStrings.Count() > 0) return;
        _memoryStrings = value;
    }
}

public void Capture()
{
    if (memoryStrings == null || memoryStrings.Count() == 0)
    {
        using (Process p = Process.GetCurrentProcess())
        {
            memoryStrings = new Dictionary<string, string>
            {
                {"privateMem", string.Format("{0:N0} K", p.PrivateMemorySize64 / 1024)},
                {"peakVm", string.Format("{0:N0} K", p.PeakVirtualMemorySize64 / 1024)},
                {"peakPaged", string.Format("{0:N0} K", p.PeakPagedMemorySize64 / 1024)},
                {"pagedSysMem", string.Format("{0:N0} K", p.PagedSystemMemorySize64 / 1024)},
                {"pagedMem", string.Format("{0:N0} K", p.PagedMemorySize64 / 1024)},
                { "nonpagedSysMem", string.Format("{0:N0} K", p.NonpagedSystemMemorySize64 / 1024)}
            };
        }
    }
}

这为我们提供了多种不变性。

如果多次致电Capture(),它将仅在第一次运行计算时。

如果您尝试在类中的其他位置覆盖字典,则在包含值时不会覆盖该字典。

如果在创建集合后尝试覆盖属性或添加值,则会收到编译时异常(在使用索引器或尝试使用.Add()方法的情况下)或运行时异常(在通过强制转换为.Add()使用IDictionary方法的情况下)。

答案 3 :(得分:-1)

public string privateMem        { get; private set; }
public string peakVM            { get; private set; }
public string peakPaged         { get; private set; }
public string pagedSysMem       { get; private set; }
public string pagedMem          { get; private set; }
public string nonpagedSysMem    { get; private set; }

这耗费了大约20秒。这有什么问题?