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.
Related
Good morning,
Suppose I have a class
public class Class
{
int something;
int[] otherThing;
}
and I want to make objects of type Class immutable. Suppose also that I have a very frequent operation which creates a new object of type Class,
public Class SomeFunction()
{
int[] Temp = new int[] { ... };
return new Class(1, Temp);
}
To avoid creating new objects too often, and since Tempis no longer accessible out of the method, is it too bad to set on the constructor
this.otherThing = Temp;
instead of
otherThing = new uint[Temp.Length];
for (int i = 0; i < Temp.Length; i++)
{
this.otherThing[i] = Temp[i];
}
?
Thank you very much.
If the constructor that does this is private its fine IMO. Since you know the content of the other array will never change you can directly use it. You could even share one instance of the array between several instances of your class if you want to without causing any problems.
A public constructor directly using a provided array is a bad idea on the other hand. Since that can be used to break immutability.
It is better to assign a copy of temp to otherThing so that any changes to otherThing will not change temp. You can also use the Array.CopyTo method for this purpose.
In addition you should seriously consider using IEnumerable<int> or IList<int> instead of int[] because arrays by nature work against the idea of immutability. Read this blog post by Eric Lippert.
The difference is that in the first option you always get a new instance and in the second one all the created "Class"es will point to the same array (!). So if you change something in the array in any Class, all the other classes are changed.
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.
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.
I found the following rather strange. Then again, I have mostly used closures in dynamic languages which shouldn't be suspectable to the same "bug". The following makes the compiler unhappy:
VoidFunction t = delegate { int i = 0; };
int i = 1;
It says:
A local variable named 'i' cannot be
declared in this scope because it
would give a different meaning to 'i',
which is already used in a 'child'
scope to denote something else
So this basically means that variables declared inside a delegate will have the scope of the function declared in. Not exactly what I would have expected. I havn't even tried to call the function. At least Common Lisp has a feature where you say that a variable should have a dynamic name, if you really want it to be local. This is particularly important when creating macros that do not leak, but something like that would be helpful here as well.
So I'm wondering what other people do to work around this issue?
To clarify I'm looking for a solution where the variables I declare in the delegete doesn't interfere with variables declared after the delegate. And I want to still be able to capture variables declared before the delegate.
It has to be that way to allow anonymous methods (and lambdas) to use local variables and parameters scoped in the containing method.
The workarounds are to either use different names for the variable, or create an ordinary method.
The "closure" created by an anonymous function is somewhat different from that created in other dynamic languages (I'll use Javascript as an example).
function thing() {
var o1 = {n:1}
var o2 = {dummy:"Hello"}
return function() { return o1.n++; }
}
var fn = thing();
alert(fn());
alert(fn());
This little chunk of javascript will display 1 then 2. The anonymous function can access the o1 variable because it exists on its scope chain. However the anonymous function has an entirely independant scope in which it could create another o1 variable and thereby hide any other further down the scope chain. Note also that all variables in the entire chain remain, hence o2 would continue to exist holding an object reference for as long as the fn varialbe holds the function reference.
Now compare with C# anonymous functions:-
class C1 { public int n {get; set;} }
class C2 { public string dummy { get; set; } }
Func<int> thing() {
var o1 = new C1() {n=1};
var o2 = new C2() {dummy="Hello"};
return delegate { return o1.n++; };
}
...
Func<int> fn = thing();
Console.WriteLine(fn());
Console.WriteLine(fn());
In this case the anonymous function is not creating a truely independant scope any more than variable declaration in any other in-function { } block of code would be (used in a foreach, if, etc.)
Hence the same rules apply, code outside the block cannot access variables declared inside the block but you cannot reuse an identifier either.
A closure is created when the anonymous function is passed outside of the function that it was created in. The variation from the Javascript example is that only those variables actually used by the anonymous function will remain, hence in this case the object held by o2 will be available for GC as soon as thing completes,
You'll also get CS0136 from code like this:
int i = 0;
if (i == 0) {
int i = 1;
}
The scope of the 2nd declaration of "i" is unambiguous, languages like C++ don't have any beef with it. But the C# language designers decided to forbid it. Given the above snippet, do you think still think that was a bad idea? Throw in a bunch of extra code and you could stare at this code for a while and not see the bug.
The workaround is trivial and painless, just come up with a different variable name.
It's because the delegate can reference variables outside the delegate:
int i = 1;
VoidFunction t = delegate { Console.WriteLine(i); };
If I remember correctly, the compiler creates a class member of the outside variables referenced in the anonymous method, in order to make this work.
Here is a workaround:
class Program
{
void Main()
{
VoidFunction t = RealFunction;
int i = 1;
}
delegate void VoidFunction();
void RealFunction() { int i = 0; }
}
Actually, the error doesn't seem to have anything to do with anonymous delegates or lamda expressions. If you try to compile the following program ...
using System;
class Program
{
static void Main()
{
// Action t = delegate
{
int i = 0;
};
int i = 1;
}
}
... you get exactly the same error, no matter whether you comment in the line or not. The error help shows a very similar case. I think it is reasonable to disallow both cases on the grounds that programmers could confuse the two variables.