C#:使方法的参数不可更改的最佳方法

时间:2014-12-29 03:49:33

标签: c#

我有一个现有的方法,如下所示: 方法体有超过1000行代码,我不能把它带到这里,只是在方法体中,如果参数的值(我的意思是 index_param )被改变,那么我会得到错误的结果。

public String calculateValue(int index_param) {
    //a highly complicated transactional method which returns a String
}

我想确保方法 body 在操作期间不会更改 index_param ,并阻止它更改参数。 你对这种情况更喜欢什么?

5 个答案:

答案 0 :(得分:3)

不幸的是,C#没有readonly的局部变量类似物。

你可以使用Code Contract Assert 需要伪后置条件,虽然我无法找到一种避免额外局部变量的方法,理论上,变异。

public String calculateValue(int index_param) {
    int __DO_NOT_MUTATE_ME = index_param;

    // a highly complicated transactional method which returns a String
    //

    Contract.Assert(index_param == __DO_NOT_MUTATE_ME, "No! Don't change the local var");
    return result;
}

编辑 - 一些调查结果
代码契约并不像预期的那样适合检测堆栈变量突变。

  • Contract.Ensures()必须位于代码块的顶部,Ensures仅用于推理返回值,而不是本地变量。
  • 因此,
  • Contract.Assert更清晰,因为它可以放在块中的任何位置。如果堆栈变量在运行时发生变异,则抛出它。
  • 如果启用了静态分析,则还有一些(后)编译时间的好处,根据附加的图像(Top显示带有错误代码的警告,bottom显示没有警告,没有突变)。但是,不是标记变异index_param(用红色箭头标记)的不良代码行,而是标记警告,我们的合同是荒谬的"考虑添加Contract.Requires(index_param + 1 == index_param);&#34 ;。嗯......
  • 您可以下载Visual Studio here的代码合约插件 - 在“属性”对话框中添加了一个附加选项卡。

enter image description here

答案 1 :(得分:3)

参数按值传递。因此,即使您将变量重新分配给方法体中的新值,原始引用也不会发生任何变化。

如果您不希望方法体甚至将变量重新分配给新值,例如java中的final int index_param或c ++中的const int index_param,则无等效在c#。

答案 2 :(得分:2)

如果你真的是偏执狂,你可以将你的价值包装在一个帮助类中,以确保你的价值不会改变

public static class ReadOnly
{
    public static ReadOnly<T> Create<T>(T val) where T : struct
    {
        return new ReadOnly<T>(val);
    }
}

public class ReadOnly<T> where T : struct
{
    private readonly T _value;

    public ReadOnly(T val)
    {
        this._value = val;
    }

    public T Value { get { return this._value; } }
}

public String calculateValue(int index_param) {
    //a highly complicated transactional method which returns a String
    var read_only_index_param = ReadOnly.Create(index_param);
    Console.WriteLine(read_only_index_param.Value);
}

答案 3 :(得分:1)

根据评论,如果是参数,则可以修改。

防止原始值被修改的唯一方法是创建方法的常量值INSIDE,而不是允许它作为参数注入方法。

public String calculateValue() {
    const int index_param = 2;
}

第二个选项是添加一个只读私有字段并将index_param参数传递给封闭类&#39;构造函数。这样,您的calculateValue()方法无法更改该字段,但这需要重构。

public class ContainingClass
{
    private readonly int _index_param;

    public ContainingClass(int index_param)
    {
        _index_param = index_param;
    }
}

这将允许您在calculateValue中使用您的私有字段,并且无法更改它,这将是编译时检查。

请注意,此私人字段仍可通过反射进行更改。也就是说,如果你有任何人不顾一切地破坏你的代码库,你手上就会遇到更大的问题。

答案 4 :(得分:0)

代码合同和/或单元测试是最佳解决方案,但另一种方法是简单地将参数分配给局部变量,并在从方法返回值之前验证参数是否未更改。如果是这样,您将不得不抛出异常,因为您的代码可能存在错误。