How to declare a local constant in C# ?
Like in Java, you can do the following :
public void f(){
final int n = getNum(); // n declared constant
}
How to do the same in C# ? I tried with readonly and const but none seems to work.
Any help would be greatly appreciated.
Thanks.
In C#, you cannot create a constant that is retrieved from a method.
Edit: dead link
http://msdn.microsoft.com/en-us/library/e6w8fe1b(VS.71).aspx
This doc should help:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/const
A constant expression is an expression that can be fully evaluated at
compile time.
Declare your local variable as an iteration variable. Iteration variables are readonly
(You didn't ask for a pretty solution).
public void f()
{
foreach (int n in new int[] { getNum() }) // n declared constant
{
n = 3; // won't compile: "error CS1656: Cannot assign to 'n' because it is a 'foreach iteration variable'"
}
}
I'm not sure why readonly and const didn't work for you since these are the keywords you need. You use const if you have a literal (except for array literals) and readonly otherwise:
public void f()
{
const int answer = 42;
}
private readonly int[] array = new int[] { 1, 2, 3, 4 };
private readonly DateTime date = DateTime.Now;
public void g()
{
Console.WriteLine(date.ToString());
}
readonly only works on class level (that is, you can only apply it to fields). Also as a consequence of const requiring a literal, it's inherently static while a readonly field can be either static or instance.
As of 2018-10-02, it isn't possible to have a readonly local in c#, but there is an open proposal for that feature that has ongoing discussion.
This article provides a useful summary.
There is a sort of workaround that requires ReSharper. You can't get readonly locals, but you can at least detect mutated ones and color them differently.
Use the Fonts and Colors item Resharper Mutable Local Variable Identifier.
For me, I have locals colored grey, and then I chose a bold white for the mutated variables (this is with a dark theme). This means that any variable that is written to more than once shows up bright compared to regular ones. You can then do what you can to try to avoid having a mutated variable, or if the method really does require one then it will at least be highlighted.
In the example you gave, you need to declare the variable as static, because you're initializing it with a method call. If you were initializing with a constant value, like 42, you can use const. For classes, structs and arrays, readonly should work.
The const keyword is used to modify a
declaration of a field or local
variable.
From MSDN.
Since C# can't enforce "const correctnes" (like c++) anyway, I don't think it's very useful. Since functions are very narrwoly scoped, it is easy not to lose oversight.
Related
I have a little question about arrays of struct in C#: lets say I have a struct Foo:
struct Foo
{
public string S;
public int X;
...
...
}
and I have an array of Foo:
Foo[] arr = ...
In one method, I use arr[i] quite often, so I'd like to keep it in a local variable (the expression for i is also a little long):
var f = arr[i]
Now, my problem is that I know structs are value type, which means assignments like this cause a copy. The struct is a little big (7 strings and a bool), so I'd prefer to avoid copying in this case.
If I am not mistaken, the only way to access the struct's fields without copying the struct is to use the array directly: arr[i].S or arr[i].X, but this quickly becomes annoying to read. I'd really like to keep the array element in a local variable, but I don't want to waste performance by copying it into the variable.
Is there a way to make something like a reference variable (similar to C++) to avoid copying? If not, than I'm curious if it's something the compiler optimizes?
How should I deal with this element? Can I put it in a local variable without copying or do I have to access it through the array to avoid copying?
Thanks in advance.
You can do this in C# 7 and later using ref local variables:
using System;
public struct LargeStruct
{
public string Text;
public int Number;
}
class Test
{
static void Main()
{
LargeStruct[] array = new LargeStruct[5];
// elementRef isn't a copy of the array value -
// it's really the variable in the array
ref LargeStruct elementRef = ref array[2];
elementRef.Text = "Hello";
Console.WriteLine(array[2].Text); // Prints hello
}
}
Of course, I'd normally recommend avoiding:
Large structs
Mutable structs
Public fields (although if it's mutable, doing that via public fields is probably best)
... but I acknowledge there are always exceptions.
If I have a method parameter that is an enum, intellisense will pick up the possible values for this enum and let me pick one. This isn't ideal for me however as it's possible people might want to use values outside of my defined set. If I make my argument a byte instead, I can then create a static class filled with consts that hold my defined set of values - the only downside is that intellisense does not know about this library of values. Is there a way to point intellisense towards a range of 'helper' values?
Technically you can assign 'invalid' values to your enum. Since the backing store of an enum is an int, you can assign any value to it:
public enum X
{
A = 0,
B = 1
}
class Program
{
static void Main(string[] args)
{
X x = (X)2;
}
}
That way, you can still have the IntelliSense support, and allow off-values. Of course, this has drawbacks too, so you have to consider whether they outweigh the pros.
A fix for that could be to assign 'custom' values in your enum, which you reserve for use later on:
public enum X
{
A = 0,
B = 1,
Custom1 = 2
}
To directly answer the Intellisense part of you question, then no I don't think it is possible to do that.
However I think you can solve your problem by using function overloading, this way you can use either type and have the benefits of both:
void Myfunction(MyEnum e)
{
MyFunction((byte)e);
}
void MyFunction(byte b)
{
// Do something
}
This one's really an offshoot of this question, but I think it deserves its own answer.
According to section 15.13 of the ECMA-334 (on the using statement, below referred to as resource-acquisition):
Local variables declared in a
resource-acquisition are read-only, and shall include an initializer. A
compile-time error occurs if the
embedded statement attempts to modify
these local variables (via assignment
or the ++ and -- operators) or
pass them as ref or out
parameters.
This seems to explain why the code below is illegal.
struct Mutable : IDisposable
{
public int Field;
public void SetField(int value) { Field = value; }
public void Dispose() { }
}
using (var m = new Mutable())
{
// This results in a compiler error.
m.Field = 10;
}
But what about this?
using (var e = new Mutable())
{
// This is doing exactly the same thing, but it compiles and runs just fine.
e.SetField(10);
}
Is the above snippet undefined and/or illegal in C#? If it's legal, what is the relationship between this code and the excerpt from the spec above? If it's illegal, why does it work? Is there some subtle loophole that permits it, or is the fact that it works attributable only to mere luck (so that one shouldn't ever rely on the functionality of such seemingly harmless-looking code)?
I would read the standard in such a way that
using( var m = new Mutable() )
{
m = new Mutable();
}
is forbidden - with reason that seem obious.
Why for the struct Mutable it is not allowed beats me. Because for a class the code is legal and compiles fine...(object type i know..)
Also I do not see a reason why changing the contents of the value type does endanger the RA. Someone care to explain?
Maybe someone doing the syntx checking just misread the standard ;-)
Mario
I suspect the reason it compiles and runs is that SetField(int) is a function call, not an assignment or ref or out parameter call. The compiler has no way of knowing (in general) whether SetField(int) is going to mutate the variable or not.
This appears completely legal according to the spec.
And consider the alternatives. Static analysis to determine whether a given function call is going to mutate a value is clearly cost prohibitive in the C# compiler. The spec is designed to avoid that situation in all cases.
The other alternative would be for C# to not allow any method calls on value type variables declared in a using statement. That might not be a bad idea, since implementing IDisposable on a struct is just asking for trouble anyway. But when the C# language was first developed, I think they had high hopes for using structs in lots of interesting ways (as the GetEnumerator() example that you originally used demonstrates).
To sum it up
struct Mutable : IDisposable
{
public int Field;
public void SetField( int value ) { Field = value; }
public void Dispose() { }
}
class Program
{
protected static readonly Mutable xxx = new Mutable();
static void Main( string[] args )
{
//not allowed by compiler
//xxx.Field = 10;
xxx.SetField( 10 );
//prints out 0 !!!! <--- I do think that this is pretty bad
System.Console.Out.WriteLine( xxx.Field );
using ( var m = new Mutable() )
{
// This results in a compiler error.
//m.Field = 10;
m.SetField( 10 );
//This prints out 10 !!!
System.Console.Out.WriteLine( m.Field );
}
System.Console.In.ReadLine();
}
So in contrast to what I wrote above, I would recommend to NOT use a function to modify a struct within a using block. This seems wo work, but may stop to work in the future.
Mario
This behavior is undefined. In The C# Programming language at the end of the C# 4.0 spec section 7.6.4 (Member Access) Peter Sestoft states:
The two bulleted points stating "if the field is readonly...then
the result is a value" have a slightly surprising effect when the
field has a struct type, and that struct type has a mutable field (not
a recommended combination--see other annotations on this point).
He provides an example. I created my own example which displays more detail below.
Then, he goes on to say:
Somewhat strangely, if instead s were a local variable of struct type
declared in a using statement, which also has the effect of making s
immutable, then s.SetX() updates s.x as expected.
Here we see one of the authors acknowledge that this behavior is inconsistent. Per section 7.6.4, readonly fields are treated as values and do not change (copies change). Because section 8.13 tells us using statements treat resources as read-only:
the resource variable is read-only in the embedded statement,
resources in using statements should behave like readonly fields. Per the rules of 7.6.4 we should be dealing with a value not a variable. But surprisingly, the original value of the resource does change as demonstrated in this example:
//Sections relate to C# 4.0 spec
class Test
{
readonly S readonlyS = new S();
static void Main()
{
Test test = new Test();
test.readonlyS.SetX();//valid we are incrementing the value of a copy of readonlyS. This is per the rules defined in 7.6.4
Console.WriteLine(test.readonlyS.x);//outputs 0 because readonlyS is a value not a variable
//test.readonlyS.x = 0;//invalid
using (S s = new S())
{
s.SetX();//valid, changes the original value.
Console.WriteLine(s.x);//Surprisingly...outputs 2. Although S is supposed to be a readonly field...the behavior diverges.
//s.x = 0;//invalid
}
}
}
struct S : IDisposable
{
public int x;
public void SetX()
{
x = 2;
}
public void Dispose()
{
}
}
The situation is bizarre. Bottom line, avoid creating readonly mutable fields.
From a method, I can pass a struct which contains an array of integers, and change the values in the array. I am not sure I understand fully why I can do this. Can someone please explain why I can change the values stored in the int[]?
private void DoIt(){
SearchInfo a = new SearchInfo();
a.Index = 1;
a.Map = new int[] { 1 };
SearchInfo b = new SearchInfo();
b.Index = 1;
b.Map = new int[] { 1 };
ModifyA(a);
ModifyB(ref b);
Debug.Assert(a.Index == 1);
Debug.Assert(a.Map[0] == 1, "why did this change?");
Debug.Assert(b.Index == 99);
Debug.Assert(b.Map[0] == 99);
}
void ModifyA(SearchInfo a) {
a.Index = 99;
a.Map[0] = 99;
}
void ModifyB(ref SearchInfo b) {
b.Index = 99;
b.Map[0] = 99;
}
struct SearchInfo {
public int[] Map;
public int Index;
}
In C#, references are passed by value. An array is not copied when passed to method or when stored in an instance of another class. - a reference to the array is passed. This means a method which recieves a reference to an array (either directly or as part of another object) can modify the elements of that array.
Unlike languages like C++, you cannot declare "immutable" arrays in C# - you can however uses classes like List which have readonly wrappers available to prevent modification to the collection.
From a method, I can pass a struct which contains an array of integers, and change the values in the array. I am not sure I understand fully why I can do this.
An array is defined as a collection of variables.
Variables, by definition, can be changed. That is why we call them "variables".
Therefore when you pass an array, you can change the contents; the contents of an array are variables.
Why can I change a struct’s int[] property without specifying “ref”?
Remember, as we discussed before in a different question, you use ref to make an alias to a variable. That is what "ref" is for -- making aliases to variables. (It is unfortunate that the keyword is the confusing "ref" -- it probably would have been more clear to make it "alias".)
From MSDN:
Do not return an internal instance of an array. This allows calling code to change the array. The following example demonstrates how the array badChars can be changed by any code that accesses the Path property even though the property does not implement the set accessor.
using System;
using System.Collections;
public class ExampleClass
{
public sealed class Path
{
private Path(){}
private static char[] badChars = {'\"', '<', '>'};
public static char[] GetInvalidPathChars()
{
return badChars;
}
}
public static void Main()
{
// The following code displays the elements of the
// array as expected.
foreach(char c in Path.GetInvalidPathChars())
{
Console.Write(c);
}
Console.WriteLine();
// The following code sets all the values to A.
Path.GetInvalidPathChars()[0] = 'A';
Path.GetInvalidPathChars()[1] = 'A';
Path.GetInvalidPathChars()[2] = 'A';
// The following code displays the elements of the array to the
// console. Note that the values have changed.
foreach(char c in Path.GetInvalidPathChars())
{
Console.Write(c);
}
}
}
You cannot correct the problem in the preceding example by making the badChars array readonly (ReadOnly in Visual Basic). You can clone the badChars array and return the copy, but this has significant performance implications.
Although your SearchInfo struct is a value type, the .Map field is holding a reference, because Array is a reference type. Think of this reference as the address pointing to the memory location where the array resides.
When you pass an instance of SearchInfo to a method, as you know, the SearchInfo gets copied. And the copy naturally contains the very same address pointing to the very same array.
In other words, copying the struct doesn't make a copy of the array, it just makes a copy of the pointer.
Well, it is passed by reference anyway, like all reference types in C#.
Neither C# nor CLR support constness, unfortunately, so the platform doesn't really know if you are allowed to change it or not. So, it has the reference, it may use it to change the value, and there's nothing to stop it from doing so.
You may see it as a language design bug, btw. It is unexpected for the user.
Why won't this work?
public static int[] GetListOfAllDaysForMonths()
{
static int[] MonthDays = new int[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};
return MonthDays;
}
I had to move the variable declaration outside of the method:
static int[] MonthDays = new int[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};
public static int[] GetListOfAllDaysForMonths()
{
return MonthDays;
}
Also, so by creating it this way, we only have one instance of this array floating around in memory? This method sits inside a static class.
C# doesn't support static locals at all. Anything static needs to be a member of a type or a type itself (ie, static class).
Btw, VB.Net does have support for static locals, but it's accomplished by re-writing your code at compile time to move the variable to the type level (and lock the initial assignment with the Monitor class for basic thread safety).
[post-accept addendum]
Personally, your code sample looks meaningless to me unless you tie it to a real month. I'd do something like this:
public static IEnumerable<DateTime> GetDaysInMonth(DateTime d)
{
d = new DateTime(d.Year, d.Month, 1);
return Enumerable.Range(0, DateTime.DaysInMonth(d.Year, d.Month))
.Select(i => d.AddDays(i) );
}
Note also that I'm not using an array. Arrays should be avoided in .Net, unless you really know why you're using an array instead of something else.
You can only create static variables in the class/struct scope. They are static, meaning they are defined on the type (not the method).
This is how C# uses the term "static", which is different from how "static" is used in some other languages.
What would be the scope of that static variable declared within the method? I don't think CLR supports method static variables, does it?
Well, apart from it not being supported, why would you want to? If you need to define something inside a method, it has local scope, and clearly doesn't need anything more than that.