【问题标题】:Making a readonly local string C#制作只读本地字符串 C#
【发布时间】:2014-07-30 14:53:28
【问题描述】:

我有一个本地字符串(文件路径),我只需要从函数中检索一次,我想确保它不再被修改。我不能使用const 关键字,因为我的字符串的值是在运行时而不是编译时确定的。所以我尝试改用 readonly 关键字,但 Visual Studio 告诉我它对我的项目无效。我怎样才能达到我想要的保护水平,最好不要再上课?

为了简单起见和公司政策,我(大幅)缩小并重命名了我的类和函数,但概念是相同的。

public class myClass
{
    private void myFunction()
    {
      readonly string filePath = HelperClass.getFilePath("123");

     //do stuff
    }
}

public static class HelperClass
{ 
    public static string getFilePath(string ID)
    {
        switch(ID)
        {
             case "123":
                 return "C:/123.txt";

             case "234":
                 return "C:/234.txt";

             default:
                 throw new Exception(ID + " is not supported");
        }
    }
}

=== 为 PS2Goat 编辑 ====

public class myClass
{
    protected SomeObject o;
    private virtual readonly string path;        

    public myClass(someObject o)
    {
        this.o = o;
        path = HelperClass.getFilePath(o.getID());
    }

    private virtual void myFunction()
    { 

     //do stuff
    }
}

public class myDerivedClass
{
    private override virtual readonly string path;        

    public myDerivedClass(someObject o) : base(o)
    {
        path = HelperClass.getFilePath(o.getID()); //ID will be different
    }

    private override void myFunction()
    { 

     //do different stuff
    }
}





public static class HelperClass
{ 
    public static string getFilePath(string ID)
    {
        switch(ID)
        {
             case "123":
                 return "C:/123.txt";

             case "234":
                 return "C:/234.txt";

             default:
                 throw new Exception(ID + " is not supported");
        }
    }
}

看,所以我遇到的这个问题是,如果我想抛出异常,我现在必须在父类的构造函数中捕获它(直到支持该类),因为父构造函数将是在派生构造函数之前调用。因此,在调用子构造函数(具有正确 ID)之前,将设置一次错误的 ID。

【问题讨论】:

  • 你不能在 getter/setter 中有一个带有逻辑的属性来防止或限制重新进入吗?
  • 字符串是不可变的,因此如果您不将任何其他字符串实例分配给您的 filePath 变量,那么它的值将不会改变。
  • 我会考虑声明一个 readonly 属性并在构造函数(或类型构造函数)中只初始化一次,但前提是 getFilePath 方法不需要花费大量时间
  • @Yuriy 是的,但我想让其他编码人员难以修改该值,它不应该在我的函数范围内进行修改。
  • 除了标记的重复项,请参见stackoverflow.com/questions/2054761/…

标签: c# .net string encapsulation protection


【解决方案1】:

您不能在方法内设置只读变量。因此应该将其提升为readonly static 字段:

public class myClass
{
    private readonly static string filePath = HelperClass.getFilePath("123");
    private void myFunction()
    {    
      //do stuff
    }
}

这将导致您的filePath 变量在第一次访问myClass 时被初始化。如果这不是您想要的,getFilePath 是一个长时间运行/昂贵的操作,并且您想等到myFunction 被调用,您可以将实现替换为System.Lazy<T>

public class myClass
{
    private readonly static Lazy<string> filePath 
            = new Lazy<string>(() => HelperClass.getFilePath("123")));
    private void myFunction()
    {   
      string path = filePath.Value;
      //do stuff
    }
}

【讨论】:

  • 好像在第一个例子中忘记指定static关键字
【解决方案2】:

readonly 表示它只能在类构造函数或实例化中设置。所以,你可以把你的逻辑改成这样:

public class myClass
{
    private readonly string _filePath;

    public myClass()
    {
        _filePath = HelperClass.getFilePath("123");
    }

    private void myFunction()
    {
      // Use your _filePath here...

     //do stuff
    }
}

public static class HelperClass
{ 
    public static string getFilePath(string ID)
    {
        switch(ID)
        {
             case "123":
                 return "C:/123.txt";

             case "234":
                 return "C:/234.txt";

             default:
                 throw new Exception(ID + " is not supported");
        }
    }
}

【讨论】:

  • 不仅在构造函数中。它只能在实例化期间设置,其中包括像@njenson 所说的内联设置(这是一个类级别的字段):readonly string filePath = HelperClass.getFilePath("123");
  • 现在假设_filePath 属性是virtual。我不确定我是否还能做到这一点。使路径成为属性(而不是添加我的保护层)而不是字段的另一个好处是我可以覆盖它。但是,现在假设myClassmyOtherClass 继承,并且其他类调用myClass 的构造函数。那么,假设基类(myClass)还不被支持,那么我就会得到一个异常,对吗?
  • @ps2goat 在我的情况下,我无法内联实例化它,因为检索 ID 的函数(在我的示例中没有硬编码)包含在传递给我的构造函数的对象中。但值得深思。
  • @audiFanatic,我只是在解释最后通牒设置为 Belogix 是不正确的。只要从构造函数中设置字段或属性,就可以了。如果继承它,您只需从子类的构造函数中调用基构造函数。在构造函数中调用的任何代码都应该允许您设置这个只读成员。
  • 嗯,好的。让我修改我的问题以更好地说明我正在尝试做的事情,然后希望我们能找到一种方法来做到这一点。修改完成后我会回帖
【解决方案3】:

您可以将要在函数定义之外声明的 readonly 变量移动。

public class myClass
    {
        readonly string filePath = HelperClass.getFilePath("123");

        private void myFunction()
        {

         //do stuff with filePath
        }
    }

【讨论】:

    【解决方案4】:

    由于这是一个变量而不是字段或属性,因此您不能将其标记为只读。但是,您可以通过使用匿名类型来“欺骗”并实现您想要的,这可以确保其属性是只读的。

    例如:

        var data = new
        {
            FileName = HelperClass.getFilePath("123");
        };
    

    【讨论】:

      【解决方案5】:

      filePath 变量提升为字段,这应该可以修复错误。局部变量不能是只读的。

      public class myClass
      {
            readonly string filePath = HelperClass.getFilePath("123");
      }
      

      【讨论】:

      • 嗯...您的代码与他所说的问题相同。将其设为可写字段并不能解决问题,因为他只希望它为空时可编辑。
      • 不,这与他所说的不起作用的问题不同。他将其提升为一个字段,而不是问题中的局部变量。
      • @siva.k 我的代码和Op的代码不一样,你可能需要再仔细阅读一遍。这会奏效。
      猜你喜欢
      • 2010-09-21
      • 1970-01-01
      • 1970-01-01
      • 2011-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-09
      • 2020-06-29
      相关资源
      最近更新 更多