C# 参数可以是常数吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2339074/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can parameters be constant?
提问by Nick Heiner
I'm looking for the C# equivalent of Java's final
. Does it exist?
我正在寻找与 Java 的final
. 它存在吗?
Does C# have anything like the following:
C# 是否有类似以下内容:
public Foo(final int bar);
In the above example, bar
is a read only variable and cannot be changed by Foo()
. Is there any way to do this in C#?
在上面的例子中,bar
是一个只读变量,不能被 更改Foo()
。有没有办法在 C# 中做到这一点?
For instance, maybe I have a long method that will be working with x
, y
, and z
coordinates of some object (ints). I want to be absolutely certain that the function doesn't alter these values in any way, thereby corrupting the data. Thus, I would like to declare them readonly.
比如,也许我还有很长的方法,将与其合作x
,y
和z
一些对象(整数)的坐标。我想绝对确定该函数不会以任何方式改变这些值,从而破坏数据。因此,我想将它们声明为只读。
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.
}
采纳答案by Corey Sunwold
Unfortunately you cannot do this in C#.
不幸的是,您不能在 C# 中执行此操作。
The const
keyword can only be used for local variables and fields.
该const
关键字只能用于局部变量和字段。
The readonly
keyword can only be used on fields.
该readonly
关键字只能领域。
NOTE: The Java language also supports having final parameters to a method. This functionality is non-existent in C#.
注意:Java 语言还支持方法的最终参数。此功能在 C# 中不存在。
from http://www.25hoursaday.com/CsharpVsJava.html
来自http://www.25hoursaday.com/CsharpVsJava.html
EDIT (2019/08/13):
I'm throwing this in for visibility since this is accepted and highest on the list. It's now kind of possible with in
parameters. See the answerbelow this one for details.
编辑(2019 年 8 月 13 日):我将其用于可见性,因为它已被接受并且在列表中最高。现在可以使用in
参数了。有关详细信息,请参阅此答案下方的答案。
回答by David Morton
If struct is passed into a method, unless it's passed by ref, it will not be changed by the method it's passed into. So in that sense, yes.
如果 struct 被传递给一个方法,除非它被 ref 传递,否则它不会被它传入的方法改变。所以从这个意义上说,是的。
Can you create a parameter whose value can't be assigned within the method or whose properties cannot be set while within the method? No. You cannot prevent the value from being assigned within the method, but you can prevent it's properties from being set by creating an immutable type.
您能否创建一个无法在方法内分配其值或在方法内无法设置其属性的参数?不可以。您不能阻止在方法中分配值,但可以通过创建不可变类型来阻止设置它的属性。
The question isn't whether the parameter or it's properties can be assigned to within the method. The question is what it will be when the method exits.
问题不在于是否可以在方法内分配参数或其属性。问题是当方法退出时会是什么。
The only time any outside data is going to be altered is if you pass a class in and change one of it's properties, or if you pass a value by using the ref keyword. The situation you've outlined does neither.
任何外部数据将被更改的唯一时间是您传入一个类并更改它的一个属性,或者您使用 ref 关键字传递值。你所概述的情况两者都没有。
回答by Joel Coehoorn
I'll start with the int
portion. int
is a value type, and in .Net that means you really are dealing with a copy. It's a really weird design constraint to tell a method "You can have a copy of this value. It's your copy, not mine; I'll never see it again. But you can't change the copy." It's implicit in the method call that copying this value is okay, otherwise we couldn't have safely called the method. If the method needs the original, leave it to the implementer to make a copy to save it. Either give the method the value or do not give the method the value. Don't go all wishy-washy in between.
我将从int
部分开始。 int
是一种值类型,在 .Net 中这意味着您确实在处理副本。告诉一个方法“你可以拥有这个值的副本。这是你的副本,不是我的;我再也看不到它了。但你不能改变副本。”这是一个非常奇怪的设计约束。在方法调用中隐含复制这个值是可以的,否则我们不能安全地调用该方法。如果该方法需要原件,请将其留给实施者制作副本以保存它。要么给方法赋值,要么不给方法赋值。不要在两者之间做所有的空想。
Let's move on to reference types. Now it gets a little confusing. Do you mean a constant reference, where the reference itself cannot be changed, or a completely locked, unchangeable object? If the former, references in .Net by default are passed by value. That is, you get a copy of the reference. So we have essentially the same situation as for value types. If the implementor will need the original reference they can keep it themselves.
让我们继续讨论引用类型。现在它变得有点混乱。你的意思是一个常量引用,引用本身不能改变,还是一个完全锁定的,不可更改的对象?如果是前者,默认情况下 .Net 中的引用是按值传递的。也就是说,您将获得参考的副本。所以我们的情况与值类型基本相同。如果实现者需要原始引用,他们可以自己保留。
That just leaves us with constant (locked/immutable) object. This might seem okay from a runtime perspective, but how is the compiler to enforce it? Since properties and methods can all have side effects, you'd essentially be limited to read-only field access. Such an object isn't likely to be very interesting.
这只是给我们留下了常量(锁定/不可变)对象。从运行时的角度来看,这似乎没问题,但是编译器如何执行它呢?由于属性和方法都可能有副作用,因此您基本上仅限于只读字段访问。这样的对象不太可能很有趣。
回答by Hans Passant
If you often run into trouble like this then you should consider "apps hungarian". The good kind, as opposed to the bad kind. While this doesn't normally tries to express constant-ness of a method parameter (that's just too unusual), there is certainly nothing that stops you from tacking an extra "c" before the identifier name.
如果您经常遇到这样的麻烦,那么您应该考虑“匈牙利应用程序”。好的种类,相对于坏的种类。虽然这通常不会试图表达方法参数的恒定性(这太不寻常了),但肯定没有什么能阻止您在标识符名称前添加额外的“c”。
To all those aching to slam the downvote button now, please read the opinions of these luminaries on the topic:
对于那些现在急于按下投票按钮的人,请阅读这些名人关于该主题的意见:
回答by Bennett Dill
Here's a short and sweet answer that will probably get a lot of down votes. I haven't read all of the posts and comments, so please forgive me if this has been previously suggested.
这是一个简短而甜蜜的答案,可能会得到很多反对票。我还没有阅读所有的帖子和评论,所以如果之前有人建议过,请原谅我。
Why not take your parameters and pass them into an object that exposes them as immutable and then use that object in your method?
为什么不获取您的参数并将它们传递给一个对象,该对象将它们公开为不可变的,然后在您的方法中使用该对象?
I realize this is probably a very obvious work around that has already been considered and the OP is trying to avoid doing this by asking this question, but I felt it should be here none-the-less...
我意识到这可能是一个非常明显的工作,已经被考虑过,OP 试图通过提出这个问题来避免这样做,但我觉得它仍然应该在这里......
Good luck :-)
祝你好运 :-)
回答by Michel Vaz Ramos
The answer: C# doesn't have the const functionality like C++.
答案是:C# 没有像 C++ 那样的 const 功能。
I agree with Bennett Dill.
我同意 Bennett Dill 的观点。
The const keyword is very useful. In the example, you used an int and people don't get your point. But, why if you parameter is an user huge and complex object that can't be changed inside that function? That's the use of const keyword: parameter can't change inside that method because [whatever reason here] that doesn't matters for that method. Const keyword is very powerful and I really miss it in C#.
const 关键字非常有用。在这个例子中,你使用了一个 int 而人们不明白你的意思。但是,为什么如果您的参数是一个无法在该函数内更改的用户庞大且复杂的对象呢?这就是 const 关键字的使用:参数不能在该方法内更改,因为 [无论这里的原因] 对该方法无关紧要。Const 关键字非常强大,我在 C# 中真的很想念它。
回答by Steve Lillis
Create an interface for your class that has only readonly property accessors. Then have your parameter be of that interface rather than the class itself. Example:
为您的类创建一个只有只读属性访问器的接口。然后让你的参数是那个接口而不是类本身。例子:
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
}
For structs, create a generic const wrapper.
对于结构,创建一个通用的 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
}
Its worth noting though, that its strange that you want to do what you're asking to do regarding structs, as the writer of the method you should expect to know whats going on in that method. It won't affect the values passed in to modify them within the method, so your only concern is making sure you behave yourself in the method you're writing. There comes a point where vigilance and clean code are the key, over enforcing const and other such rules.
不过值得注意的是,作为方法的作者,你想要做你要求做的关于结构的事情,这很奇怪,作为方法的作者,你应该知道该方法中发生了什么。它不会影响传入的值以在方法中修改它们,因此您唯一关心的是确保您在编写的方法中表现自己。在这一点上,警惕和干净的代码是关键,而不是强制执行 const 和其他此类规则。
回答by SoLaR
I know this might be little late. But for people that are still searching other ways for this, there might be another way around this limitation of C# standard. We could write wrapper class ReadOnly<T> where T : struct. With implicit conversion to base type T. But only explicit conversion to wrapper<T> class. Which will enforce compiler errors if developer tries implicit set to value of ReadOnly<T> type. As I will demonstrate two possible uses below.
我知道这可能有点晚了。但是对于仍在为此寻找其他方法的人来说,可能有另一种方法可以解决 C# 标准的这种限制。我们可以编写包装类 ReadOnly<T> 其中 T : struct。隐式转换为基本类型 T。但仅显式转换为 wrapper<T> 类。如果开发人员尝试隐式设置为 ReadOnly<T> 类型的值,这将强制编译器错误。我将在下面演示两种可能的用途。
USAGE 1 required caller definition to change. This usage will have only use in testing for correctness of your "TestCalled" functions code. While on release level/builds you shouldn't use it. Since in large scale mathematical operations might overkill in conversions, and make your code slow. I wouldn't use it, but for demonstration purpose only I have posted it.
用法 1 需要更改调用者定义。此用法仅用于测试“TestCalled”函数代码的正确性。在发布级别/构建时,您不应该使用它。因为在大规模数学运算中可能会在转换中过度使用,并使您的代码变慢。我不会使用它,但仅出于演示目的我发布了它。
USAGE 2 which I would suggest, has Debug vs Release use demonstrated in TestCalled2 function. Also there would be no conversion in TestCaller function when using this approach, but it requires a little more of coding of TestCaller2 definitions using compiler conditioning. You can notice compiler errors in debug configuration, while on release configuration all code in TestCalled2 function will compile successfully.
我建议的 USAGE 2 在 TestCalled2 函数中演示了 Debug 与 Release 的使用。使用这种方法时,也不会在 TestCaller 函数中进行转换,但它需要使用编译器条件对 TestCaller2 定义进行更多编码。您可以在调试配置中注意到编译器错误,而在发布配置中,TestCalled2 函数中的所有代码都将成功编译。
using System;
using System.Collections.Generic;
public class ReadOnly<VT>
where VT : struct
{
private VT value;
public ReadOnly(VT value)
{
this.value = value;
}
public static implicit operator VT(ReadOnly<VT> rvalue)
{
return rvalue.value;
}
public static explicit operator ReadOnly<VT>(VT rvalue)
{
return new ReadOnly<VT>(rvalue);
}
}
public static class TestFunctionArguments
{
static void TestCall()
{
long a = 0;
// CALL USAGE 1.
// explicite cast must exist in call to this function
// and clearly states it will be readonly inside TestCalled function.
TestCalled(a); // invalid call, we must explicit cast to ReadOnly<T>
TestCalled((ReadOnly<long>)a); // explicit cast to ReadOnly<T>
// CALL USAGE 2.
// Debug vs Release call has no difference - no compiler errors
TestCalled2(a);
}
// ARG USAGE 1.
static void TestCalled(ReadOnly<long> a)
{
// invalid operations, compiler errors
a = 10L;
a += 2L;
a -= 2L;
a *= 2L;
a /= 2L;
a++;
a--;
// valid operations
long l;
l = a + 2;
l = a - 2;
l = a * 2;
l = a / 2;
l = a ^ 2;
l = a | 2;
l = a & 2;
l = a << 2;
l = a >> 2;
l = ~a;
}
// ARG USAGE 2.
#if DEBUG
static void TestCalled2(long a2_writable)
{
ReadOnly<long> a = new ReadOnly<long>(a2_writable);
#else
static void TestCalled2(long a)
{
#endif
// invalid operations
// compiler will have errors in debug configuration
// compiler will compile in release
a = 10L;
a += 2L;
a -= 2L;
a *= 2L;
a /= 2L;
a++;
a--;
// valid operations
// compiler will compile in both, debug and release configurations
long l;
l = a + 2;
l = a - 2;
l = a * 2;
l = a / 2;
l = a ^ 2;
l = a | 2;
l = a & 2;
l = a << 2;
l = a >> 2;
l = ~a;
}
}
回答by Max
This is now possible in C# version 7.2:
这现在可以在 C# 7.2 版中实现:
You can use the in
keyword in the method signature. MSDN documentation.
您可以in
在方法签名中使用关键字。MSDN 文档。
The in
keyword should be added before specifying a method's argument.
该in
关键字应在指定方法的参数之前加入。
Example, a valid method in C# 7.2:
示例,C# 7.2 中的有效方法:
public long Add(in long x, in long y)
{
return x + y;
}
While the following is not allowed:
虽然以下情况是不允许的:
public long Add(in long x, in long y)
{
x = 10; // It is not allowed to modify an in-argument.
return x + y;
}
Following error will be shown when trying to modify either x
or y
since they are marked with in
:
尝试修改x
或y
因为它们标有以下错误时将显示以下错误in
:
Cannot assign to variable 'in long' because it is a readonly variable
无法分配给“in long”变量,因为它是只读变量
Marking an argument with in
means:
用以下in
方式标记论点:
This method does not modify the value of the argument used as this parameter.
此方法不会修改用作此参数的参数值。