Reading a book (VS 2010), it says that commands (statements) in .NET Csharp cannot exist outside of method.
I am wondering - field declaration etc, these are commands, are they not? And they exist at class level. Can somebody elaborate at this a bit?
If you mean:
class Foo
{
int count = 0;
StringBuilder buffer = new StringBuilder();
}
The count and buffer are declarations using initializer expressions . But this code contains no statements.
A field initialiser is written with the code outside a method, but the compiler puts that code inside the constructor.
So a field initialiser like this:
class Foo {
int Bar = 42;
}
is basiclally a field and an initialiser in the constructor:
class Foo {
int Bar;
Foo() {
Bar = 42;
}
}
There's no such concept as a "command" in C#.
And a static / instance variable declaration isn't categorized as a statement within C# - it's a field-declaration (which is a type of class-member-declaration) as per the C# spec. See section 10.5 of the C# 4 spec for example.
Now the statements which declare local variables are statements, as defined by declaration-statement in the spec (section 8.5). They're only used for locals though. See section B.2.5 for a complete list of statement productions within C# 4.
Basically, the C# spec defines the terminology involved - so while you might think informally of "commands" and the like, in a matter of correctness the C# spec is the source of authority. (Except for where it doesn't say what the language designers meant to say, of course. That's pretty rare.)
As you said they're declarations, a statement is one which actually gets something done.
No, they're declarations. Class member declarations, to be precise.
And it's perfectly legal for those to exist outside of a method. Otherwise, you couldn't declare a method in the first place!
By "statements", the book is telling you that you can't have things like method calls outside of a method. For example, the following code is illegal:
public void DoSomething()
{
// Do something here...
}
MessageBox.Show("This statement is not allowed because it is outside a method.");
Classes, namespace, fields declarations are not declarations statements.
A field can be initialised outside a method with an expression but while an expression is a statement there are lots of statements that are not expressions (eg. if).
It all comes down to how the language grammar defines the terms, and the way C# does it is pretty common (eg. very similar to C and C++).
Related
I can't find an answer to my problem. In dotNet/C#, is it possible to check if a variable was declared to some type and if not, declare it?
Thanks
[Edit] In this case, C# is used as a preexecute language in Open Text CMS. C# code can be used in any module. Using a non-declared variable throws hard to debug errors, as does double-declaring a variable. That's why I'd like to check.
[Edit2] Yes it is most probably compiled somewhere, but the errors are thrown (or rather not thrown) on runtime
[Edit3] Further explanation:
In Open Text, every page can hold several modules, several instances of a module and the same instance of a module several times. In each module, you can use C# as a "pre-execute" language. This is mostly really easy scripting to maneuver around the failings of OpenText. You introduce small variables, set them to true or false, and three lines later write a condition based on the variable. We could (and do) declare a bunch of variables in an initialization block of the page, but since there are so many, it would help to be able to check if a variable was declared and if not, declare it.
I like the idea of changing this to a key/value dictionary but this is a really large site with loads of pages/modules and instances and I'm looking for a working solution without changing the whole thing.
The actual code is really simple most oft he time:
var hasHeadline = false; // this will throw an error if hasHeadline was declared before
hasHeadline = true; // if some CMS condition is met. this will throw an error if hasHeadline wasn't declared
if(hasHeadline) { ** CMS code ** }
As I said, this will show up in multiple instances over which I don't have full control. The resulting "error" will be that the whole code block is stripped from the page.
Declare a single variable that is dynamic, e.g. an ExpandoObject.
dynamic Globals = new ExpandoObject();
Use this variable to store all of your global state.
Globals.hasHeadline = false; //No declaration needed, so
Globals.hasHeadline = true; //no chance of a duplicate declaration
There's no need to. C# is a statically typed programming language ("type" refers to more than just class, struct, and interface: "static typing" means the "types" (shapes) of data, objects and values in your program are known
statically - i.e. at compile-time). If something isn't declared in scope then your code simply won't compile.
This also applies to locals (local variables, method parameters, etc).
This won't compile:
class Foo
{
void Foo( String x )
{
if( z > 0 ) { // `z` isn't declared as a field, parameter or local.
// ...
}
}
}
Similarly, this won't compile:
class Foo
{
public string x;
}
class Bar
{
void Baz( Foo foo )
{
if( foo.z > 0 ) { // `z` is not declared in `Foo`
}
}
}
That said, there are some things you do need to check-before-using in C#, such as:
Nullable references or nullable values.
Entries in a Dictionary or other keyed collection.
Type-checking when you want a known subclass or interface (As C# still does not natively support algebraic types, grrrr)
...but none of those involve checking for declarations.
In any c# class this is allowed
Class Program
{
Dub obj=new Dub()
}
But not this
Class Program
{
Dub obj1= null;
Obj1=new Dub();
}
Try this in class only not in any function.
The language is designed to separate your "things" (class fields and class properties) from how to use them (methods). However, certain things are just syntactic sugar that allows you to be more concise.
In fact, your code
Class Program
{
Dub obj=new Dub()
}
is functionally (and semantically) equivalent to this
Class Program
{
Dub obj;
public Program()
{
obj = new Dub();
}
}
because it declares a field (Dub obj is the portion of code that does that) and then initializes it when it is constructed (= new Dub() is how you say that you want it initialized).
You may wonder why you have two ways to do the same things, but the point is that what you are writing in the initializer must be an expression that can be assigned to the field which is being initialized.
It is a constrained thing that you can use to have less code to write and review when things are easy. If that is not suitable, you can use the constructor, where you are free to do all the fancy things that are not allowed in the initializer.
Simply put, Instructions are almost unconstrained statements that can be used inside methods. An expression is an instruction, but not vice versa. Initializers require expressions by design.
For more information on initializers, you can have a look at Field MSDN documentation, where everything is explained with more details and samples.
This question already has answers here:
Implicit typing; why just local variables?
(6 answers)
Closed 8 years ago.
class A
{
A()
{
var x = 5; // this is allowed
}
var _x = 5; // the compiler is unhappy
}
I guess the compiler must be able to deduce the type for the member variable just the same way it does it for the local one. So what's the difference?
Eric Lippert answered your question right here: Why no var on fields?
Basically, for the general case it would require re-writing the C# compiler, as the way it currently does type inference would not work for cycles of var field variable assignments.
The var keyword was designed for anonymous types, which can only be used inside of a method.
Also, you're wrong; the compiler cannot always deduce a var field.
What happens if you compile the following:
class A {
public readonly var value = B.value;
}
class B {
public readonly var value = B.value;
}
This situation is impossible to recreate with local variables, since a variable cannot be referenced before it's defined.
The general problem here is that you're asking the compiler to consume type information while it's still generating that information.
Eric Lippert explains in greater depth.
I see two reasons:
It might be desirable to make the declaration of types in a public interface explicit
It's hard to implement. The C# compiler compiles in multiple phases.
At first it parses everything apart from method bodies so it knows about everything outside of function bodies. Then it can use that information to compile method bodies individually. What happens while compiling one method body hasn't much effect on what happens when compiling other method bodies.
If you could use var for fields the expression body of the field initializer would affect the type of the field and thus many other methods. So it doesn't fit the compiler design well.
This is a guess, but initialization of class-level fields must be done as part of the initialization (constructor) process for a Type, whereas initialization of a method-level variable happens when the method's stack frame is constructed. Perhaps the distinction is related to how these processes are compiled (how their implementation is created) inside the framework.
This is a purely academic question - I have found a getaround easily enough.
While porting a VB.Net class to C#, I came upon the declaration of a field in a class which used the this keyword as a parameter in a new() statement. The compiler said the "Keyword 'this' is not available in the current context' (the VB compiler saw no problem with this state of affairs). I easily got around this by moving the field's initialization to the contructor of the class.
edit: after reading comments, I added the following code block
public class cTransactions
{
private List Trans = new List();
private List Archive = new List();
private cDDs Debits = new cDDs(this); // complier error
//Keyword 'this' is not available in the current context
private string path = Directory.GetCurrentDirectory() + "\";
private bool dirty = false;
private int LastID;
// followed by Property declarations, ctor, methods etc.
//...
}
However, I cannot find any reference to the keyword 'this' not being available before the execution of a class' constructor (though I may have missed that revelation in the 500+ pages of the language specification). Is this the case or should I be looking some error in one of the lines prior to the field declaration?
Looking at the C# Language specification section 7.6.7:
7.6.7 This access
A this-access is permitted only in the block of an instance
constructor, an instance method, or an instance accessor. ... (specifics omitted) ...
Use of this in a primary-expression in a context other than the ones
listed above is a compile-time error. In particular, it is not
possible to refer to this in a static method, a static property
accessor, or in a variable-initializer of a field declaration.
Therefore, using it in a variable-initializer in the example above is a compile-time error. To fix it, move the initialization into the constructor.
Like for instance:
if ( this.IsValid )
{
Matrix matrix = new Matrix();
}
Matrix matrix = new Matrix();
The compiler warns me saying:
"A local variable named 'matrix' cannot be declared in this scope because it would give a different meaning to 'matrix', which is already used in a 'child' scope to denote something else.
Aren't these variables in different scopes, so I wouldn't be able to access the first matrix from outside the if statement anyway?
UPDATE: The answer below from 2011 is correct for earlier versions of C#; in more recent versions, the rule described the answer has been removed from C#. The design team determined that the rule caused more confusion amongst developers leading to questions like this one than the buggy programs prevented would warrant, even after I greatly improved the error messages to more clearly diagnose the problem.
The answers given so far are very confusing. The correct analysis of the problem starts by reading the error message. The error message is telling you what is actually wrong:
"A local variable named 'matrix' cannot be declared in this scope because it would give a different meaning to 'matrix', which is already used in a 'child' scope to denote something else.
Read that carefully. It is telling you precisely which rule of C# is being violated, namely that you are not allowed to use the same name to refer to two different things in the same scope. (Actually, the error message is slightly wrong; it should say "local variable declaration space" where it says "scope", but that is pretty wordy.)
This rule is documented in the C# 4.0 specification, section 7.6.2.1: Simple names, Invariant meaning in blocks.
(It is also illegal to have two local variables of the same name in overlapping declaration spaces. The compiler could be reporting that error as well, but it reports the more general error in this case.)
Aren't these variables in different scopes, so I wouldn't be able to access the first matrix from outside the if statement anyway?
Yes. That statement is true but irrelevant. The error here is that the same simple name has been used to refer to two different things in the same local variable declaration space.
Consider this scenario:
class C
{
int x;
void M()
{
x = 10; // means "this.x"
for(whatever)
{
int x = whatever;
}
}
}
Same deal. The error here is that the simple name "x" was used in the outer declaration space to refer to this.x, and was used in the inner declaration space to mean "local variable". Using the same simple name to refer to two different things in the same declaration space -- remember, the inner declaration space is a part of the outer one -- is both confusing and dangerous, and is therefore illegal.
It is confusing for obvious reasons; one has a reasonable expectation that a name will mean the same thing everywhere throughout the declaration space in which it is first used. It is dangerous because small code edits are prone to changing the meaning:
class C
{
int x;
void M()
{
int x;
x = 10; // no longer means "this.x"
for(whatever)
{
x = whatever;
}
}
}
If the declaration spaces in which the simple names are first used are not overlapping then it is legal for the simple names to refer to different things:
class C
{
int x;
void M()
{
{
x = 10; // means "this.x"
}
for(whatever)
{
int x = whatever; // Legal; now the
}
}
}
For more information, and an amusing story about fried food, see
http://blogs.msdn.com/b/ericlippert/archive/tags/simple+names/
It is my belief that this is done in order to avoid obscure mistakes or code that's hard to read.
Using the same name of variable between a method scope and a child scope can lead to code that's very hard to read, since the variable type and, worse, meaning, can change and the only hint to the reader will be type declaration keyword before the variable.
However, I can also tell you that the IL generated for methods by the C# compiler will stick all variable declarations at the top, so maybe this decision driver was to simplify the variable parsing tree for the compiler.
In fact, you can find this at MSDN:
The scope of a name is the region of
program text within which it is
possible to refer to the entity
declared by the name without
qualification of the name. Scopes can
be nested, and an inner scope may
redeclare the meaning of a name from
an outer scope. (This does not,
however, remove the restriction
imposed by Section 3.3 that within a
nested block it is not possible to
declare a local variable with the same
name as a local variable in an
enclosing block.) The name from the
outer scope is then said to be hidden
in the region of program text covered
by the inner scope, and access to the
outer name is only possible by
qualifying the name.
Emphasis added.
And, from Section 3.3:
Each block or switch-block creates a
different declaration space for local
variables and constants. Names are
introduced into this declaration space
through local-variable-declarations
and local-constant-declarations. If a
block is the body of an instance
constructor, method, or operator
declaration, or a get or set accessor
for an indexer declaration, the
parameters declared in such a
declaration are members of the block's
local variable declaration space. The
local variable declaration space of a
block includes any nested blocks.
Thus, within a nested block it is not
possible to declare a local variable
with the same name as a local variable
in an enclosing block.
Emphasis added.
So, the thing is that while the scopes are different, the variable space is the same.
You can always do this...
void YourMethod()
{
if ( this.IsValid )
{
Matrix matrix = new Matrix();
}
{
Matrix matrix = new Matrix();
}
}
...Each set of braces {} allows you to nest another level of scope. The issue you are having is the fact that nested scopes include the scope of their parents. If you declare a siblng scope it will be able to resuse variables within the same parent. But as others have pointed out this may become confusing later.
Imagine a human being trying to read this code.
From the point of view of another developer trying to read your code, can you see how confusing it would be to have two different variables with the same name? Even if they are representing the same thing, it's just too hard to deal with two things with the same name.
Matrix matrix = new Matrix();
if ( this.IsValid )
{
Matrix matrix = new Matrix();
}
Imagine it instead written like that, it is a bit more obvious I would think why this is not allowed since the second instance should obviously be considered a clash. Not being able to access the outer variables within child scopes would be bad.
From MSDN "A: This is correct behavior, and is covered in section 3.7 of the language spec. It says, “The scope of a local variable declared in a local-variable-declaration (8.5.1) is the block in the which the declaration occurs”." ... "This behavior is inteded to make incorrect re-use of variable names (such as in a cut and paste) less likely." (http://blogs.msdn.com/b/csharpfaq/archive/2004/05/18/why-can-t-i-use-the-same-variable-as-an-inner-loop-does.aspx)