参数可以不变吗?

Nic*_*ner 79 c# const parameter-passing readonly

我正在寻找与Java相当的C#final.它存在吗?

C#是否包含以下内容:

public Foo(final int bar);
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,bar是一个只读变量,不能更改Foo().有没有办法在C#中做到这一点?

比如,也许我还有很长的方法,将与其合作x,yz一些对象(整数)的坐标.我想绝对肯定该函数不会以任何方式改变这些值,从而破坏数据.因此,我想宣读它们.

public Foo(int x, int y, int z) {
     // do stuff
     x++; // oops. This corrupts the data. Can this be caught at compile time?
     // do more stuff, assuming x is still the original value.
}
Run Code Online (Sandbox Code Playgroud)

Cor*_*old 59

不幸的是你无法在C#中做到这一点.

const关键字只能用于局部变量和字段.

readonly关键字只能用于字段.

注意:Java语言还支持为方法提供最终参数.此功能在C#中不存在.

来自http://www.25hoursaday.com/CsharpVsJava.html

  • @John Saunders不幸因为Rosarch正在寻找一个不存在的功能. (31认同)
  • @John:这个方法并不是一成不变的.这就是问题所在. (7认同)
  • 它只是在这种方法范围之外的常数.忽略它是通过引用还是通过值传递,Rosarch不希望参数在方法的范围内更改.这是关键的区别. (5认同)
  • @silky:读他的帖子,这不是他要求的.他要求确保方法不会改变实际参数. (5认同)
  • @Hi-Angel:在评判之前先了解更多有关 C# 的知识。仅复制值类型对象:`int`、`double`、`struct`。请注意,C# 中的“struct”与 C++ 中的“struct”不同。 (2认同)

Max*_*Max 24

现在可以在C#7.2版中实现:

您可以in在方法签名中使用关键字.MSDN文档.

in关键字应在指定方法的参数之前加入.

例如,C#7.2中的有效方法:

public long Add(in long x, in long y)
{
    return x + y;
}
Run Code Online (Sandbox Code Playgroud)

虽然不允许以下内容:

public long Add(in long x, in long y)
{
    x = 10; // It is not allowed to modify an in-argument.
    return x + y;
}
Run Code Online (Sandbox Code Playgroud)

尝试修改时会显示以下错误,x或者y因为它们标记为in:

无法分配变量'in long',因为它是一个只读变量

in手段标记参数:

此方法不会修改用作此参数的参数的值.

  • **请注意**,它仅适用于结构/值,不适用于类,在类中您可以修改引用的实例,因此情况会更糟。并且您不会收到任何警告。谨慎使用。http://blog.dunnhq.com/index.php/2017/12/15/readonly-parameters-in-ca-step-closer-to-immutability/ (7认同)
  • 当然,它对于引用类型没有用。对这些类型的参数使用“in”关键字,只会阻止分配给它们。不阻止修改其可访问字段或属性!我对吗? (5认同)

Joe*_*orn 8

我将从这int部分开始. int是一种值类型,在.Net中,这意味着您真正在处理副本.这是一个非常奇怪的设计约束,告诉方法"你可以得到这个值的副本.这是你的副本,而不是我的副本;我永远不会再看到它了.但你无法改变副本." 在方法调用中隐含了复制此值是可以的,否则我们无法安全地调用该方法.如果该方法需要原始文件,请将其留给实施者进行复制以保存原文.要么给方法赋值,要么不给方法赋值.不要在两者之间全力以赴.

让我们继续讨论类型.现在它有点令人困惑.你的意思是一个恒定的引用,其中引用本身不能被更改,或者一个完全锁定,不可更改的对象?如果是前者,默认情况下.Net中的引用是按值传递的.也就是说,您获得了参考文献的副本.因此,我们与价值类型的情况基本相同.如果实现者需要原始引用,他们可以自己保留它.

这只是给我们留下了常量(锁定/不可变)对象.从运行时的角度来看,这似乎没什么问题,但编译器如何强制执行呢?由于属性和方法都有副作用,因此基本上只限于只读字段访问.这样的对象不太可能非常有趣.

  • 我因为你误解了这个问题而否决了你;这不是在调用后更改值,而是在其中更改值。 (2认同)
  • @silky - 我没有误解这个问题.我也在谈论这个功能.我说发送到一个函数是一个奇怪的限制,因为它并没有真正阻止任何事情.如果有人忘记更改原始参数,他们就会忘记更改副本. (2认同)

小智 8

答案:C#没有像C++那样的const功能.

我同意Bennett Dill的观点.

const关键字非常有用.在这个例子中,你使用了一个int,人们不明白你的观点.但是,为什么如果你的参数是一个用户庞大而复杂的对象,在该函数内部无法更改?这是使用const关键字:参数不能在该方法内部进行更改,因为[此处无论什么原因]对该方法无关紧要.Const关键字非常强大,我真的很想念它在C#中.


Ben*_*ill 7

这是一个简短而又甜蜜的答案,可能会得到很多票数.我没有阅读所有的帖子和评论,所以请原谅我,如果以前曾建议的那样.

为什么不把你的参数传递给一个将它们公开为不可变的对象,然后在你的方法中使用该对象?

我意识到这可能是一个非常明显的工作,已经考虑过,OP试图通过提出这个问题来避免这样做,但我觉得它应该在这里,不过不...

祝好运 :-)


Ste*_*lis 5

为您的类创建一个仅具有只读属性访问器的接口。然后让您的参数属于该接口,而不是类本身。例:

public interface IExample
{
    int ReadonlyValue { get; }
}

public class Example : IExample
{
    public int Value { get; set; }
    public int ReadonlyValue { get { return this.Value; } }
}


public void Foo(IExample example)
{
    // Now only has access to the get accessors for the properties
}
Run Code Online (Sandbox Code Playgroud)

对于结构,创建一个通用的const包装器。

public struct Const<T>
{
    public T Value { get; private set; }

    public Const(T value)
    {
        this.Value = value;
    }
}

public Foo(Const<float> X, Const<float> Y, Const<float> Z)
{
// Can only read these values
}
Run Code Online (Sandbox Code Playgroud)

但是,值得注意的是,作为方法的编写者,您想要完成关于结构的要求,这很奇怪,您应该期望知道该方法的工作。它不会影响传入的值以在方法中修改它们,因此您唯一需要考虑的是确保自己在编写的方法中表现得很好。在强制执行const和其他此类规则方面,警惕性和整洁的代码是关键。