If you use an initializer list to create a struct, do the members you leave out get a known default value?
public struct Testing
{
public int i;
public double d;
public string s;
}
Testing test = new Testing { s="hello" };
I found a link at Microsoft that implies it but does not state so explicitly: Default Values Table (C# Reference).
A small test program shows that it does not generate a compiler error and produces the expected results. I know better than to rely on simple tests for guarantees though. http://ideone.com/nqFBIZ
Yes, they contain default(T) where T is the type of the value.
Object references will be null.
Excerpt:
As described in Section 5.2, several kinds of variables are
automatically initialized to their default value when they are
created. For variables of class types and other reference types, this
default value is null. However, since structs are value types that
cannot be null, the default value of a struct is the value produced by
setting all value type fields to their default value and all reference
type fields to null.
Taken from here:
http://msdn.microsoft.com/en-us/library/aa664475(v=vs.71).aspx
I remember when studying the MOC for the certification that they explicitly state this. It is a guaranteed feature of the language.
To expand on pid's answer:
test = new Testing { s = hello }
is specified as having the semantics of:
Testing temp = new Testing();
temp.s = "hello";
test = temp;
The default constructor of a value type is documented as the constructor which sets all the fields of the instance to their default values.
More generally, the C# language requires that any constructor of a value type have the property that all fields be definitely assigned before the constructor terminates normally.
Now, if no constructor is called then there are two cases. If the variable is initially assigned then the variable acts the same as though the default constructor was called. For example, if you say
Testing[] test = new Testing[1];
Then test[0] is initialized to the default value the same as if you'd said
Testing[] test = new Testing[1] { new Testing() };
If the variable is not initially assigned, for example, a local variable, then you are required to definitely assign all the fields before you read them. That is, if we have a local:
Testing test;
test.s = "hello";
Console.WriteLine(test.d); // ERROR, test.d has not been written yet.
Note also that mutable structs are a worst practice in C#. Instead, make a public constructor that sets all the fields, make the fields private, and put property getters on top of them.
Related
My code is the following
int tmpCnt;
if (name == "Dude")
tmpCnt++;
Why is there an error "Use of unassigned local variable tmpCnt"?
I know I didn't explicitly initialize it, but due to Default Value Table a value type is initialized with 0 anyway. The reference also reminds me:
Remember that using uninitialized variables in C# is not allowed.
But why do I have to do it explicitly if it's already done by default? Wouldn't it gain performance if I wouldn't have to do it?
Local variables aren't initialized. You have to manually initialize them.
Members are initialized, for example:
public class X
{
private int _tmpCnt; // This WILL initialize to zero
...
}
But local variables are not:
public static void SomeMethod()
{
int tmpCnt; // This is not initialized and must be assigned before used.
...
}
So your code must be:
int tmpCnt = 0;
if (name == "Dude")
tmpCnt++;
So the long and the short of it is, members are initialized, locals are not. That is why you get the compiler error.
Default assignments apply to class members, but not to local variables. As Eric Lippert explained it in this answer, Microsoft could have initialized locals by default, but they choose not to do it because using an unassigned local is almost certainly a bug.
The following categories of variables are classified as initially unassigned:
Instance variables of initially unassigned struct variables.
Output parameters, including the this variable of struct instance constructors.
Local variables , except those declared in a catch clause or a foreach statement.
The following categories of variables are classified as initially assigned:
Static variables.
Instance variables of class instances.
Instance variables of initially assigned struct variables.
Array elements.
Value parameters.
Reference parameters.
Variables declared in a catch clause or a foreach statement.
Local variables don't have a default value.
They have to be definitely assigned before you use them. It reduces the chance of using a variable you think you've given a sensible value to, when actually it's got some default value.
The default value table only applies to initializing a variable.
Per the linked page, the following two methods of initialization are equivalent...
int x = 0;
int x = new int();
In your code, you merely defined the variable, but never initialized the object.
A very dummy mistake, but you can get this with a class too if you didn't instantiate it.
BankAccount account;
account.addMoney(5);
The above will produce the same error whereas:
class BankAccount
{
int balance = 0;
public void addMoney(int amount)
{
balance += amount;
}
}
Do the following to eliminate the error:
BankAccount account = new BankAccount();
account.addMoney(5);
Local variables are not automatically initialized. That only happens with instance-level variables.
You need to explicitly initialize local variables if you want them to be initialized. In this case, (as the linked documentation explains) either by setting the value of 0 or using the new operator.
The code you've shown does indeed attempt to use the value of the variable tmpCnt before it is initialized to anything, and the compiler rightly warns about it.
See this thread concerning uninitialized bools, but it should answer your question.
Local variables are not initialized unless you call their constructors (new) or assign them a value.
IEnumerable<DateTime?> _getCurrentHolidayList; //this will not initailize
Assign value(_getCurrentHolidayList) inside the loop
foreach (HolidaySummaryList _holidayItem in _holidayDetailsList)
{
if (_holidayItem.CountryId == Countryid)
_getCurrentHolidayList = _holidayItem.Holiday;
}
After your are passing the local varibale to another method like below.
It throw error(use of unassigned variable). eventhough nullable mentioned in time of decalration.
var cancelRescheduleCondition = GetHolidayDays(_item.ServiceDateFrom, _getCurrentHolidayList);
if you mentioned like below, It will not throw any error.
IEnumerable<DateTime?> _getCurrentHolidayList =null;
While value types have default values and can not be null, they also need to be explicitly initialized in order to be used. You can think of these two rules as side by side rules.
Value types can not be null โ the compiler guarantees that.
If you ask how, the error message you got is the answer. Once you call their constructors, they got initialized with their default values.
int tmpCnt; // Not accepted
int tmpCnt = new Int(); // Default value applied tmpCnt = 0
My code is the following
int tmpCnt;
if (name == "Dude")
tmpCnt++;
Why is there an error "Use of unassigned local variable tmpCnt"?
I know I didn't explicitly initialize it, but due to Default Value Table a value type is initialized with 0 anyway. The reference also reminds me:
Remember that using uninitialized variables in C# is not allowed.
But why do I have to do it explicitly if it's already done by default? Wouldn't it gain performance if I wouldn't have to do it?
Local variables aren't initialized. You have to manually initialize them.
Members are initialized, for example:
public class X
{
private int _tmpCnt; // This WILL initialize to zero
...
}
But local variables are not:
public static void SomeMethod()
{
int tmpCnt; // This is not initialized and must be assigned before used.
...
}
So your code must be:
int tmpCnt = 0;
if (name == "Dude")
tmpCnt++;
So the long and the short of it is, members are initialized, locals are not. That is why you get the compiler error.
Default assignments apply to class members, but not to local variables. As Eric Lippert explained it in this answer, Microsoft could have initialized locals by default, but they choose not to do it because using an unassigned local is almost certainly a bug.
The following categories of variables are classified as initially unassigned:
Instance variables of initially unassigned struct variables.
Output parameters, including the this variable of struct instance constructors.
Local variables , except those declared in a catch clause or a foreach statement.
The following categories of variables are classified as initially assigned:
Static variables.
Instance variables of class instances.
Instance variables of initially assigned struct variables.
Array elements.
Value parameters.
Reference parameters.
Variables declared in a catch clause or a foreach statement.
Local variables don't have a default value.
They have to be definitely assigned before you use them. It reduces the chance of using a variable you think you've given a sensible value to, when actually it's got some default value.
The default value table only applies to initializing a variable.
Per the linked page, the following two methods of initialization are equivalent...
int x = 0;
int x = new int();
In your code, you merely defined the variable, but never initialized the object.
A very dummy mistake, but you can get this with a class too if you didn't instantiate it.
BankAccount account;
account.addMoney(5);
The above will produce the same error whereas:
class BankAccount
{
int balance = 0;
public void addMoney(int amount)
{
balance += amount;
}
}
Do the following to eliminate the error:
BankAccount account = new BankAccount();
account.addMoney(5);
Local variables are not automatically initialized. That only happens with instance-level variables.
You need to explicitly initialize local variables if you want them to be initialized. In this case, (as the linked documentation explains) either by setting the value of 0 or using the new operator.
The code you've shown does indeed attempt to use the value of the variable tmpCnt before it is initialized to anything, and the compiler rightly warns about it.
See this thread concerning uninitialized bools, but it should answer your question.
Local variables are not initialized unless you call their constructors (new) or assign them a value.
IEnumerable<DateTime?> _getCurrentHolidayList; //this will not initailize
Assign value(_getCurrentHolidayList) inside the loop
foreach (HolidaySummaryList _holidayItem in _holidayDetailsList)
{
if (_holidayItem.CountryId == Countryid)
_getCurrentHolidayList = _holidayItem.Holiday;
}
After your are passing the local varibale to another method like below.
It throw error(use of unassigned variable). eventhough nullable mentioned in time of decalration.
var cancelRescheduleCondition = GetHolidayDays(_item.ServiceDateFrom, _getCurrentHolidayList);
if you mentioned like below, It will not throw any error.
IEnumerable<DateTime?> _getCurrentHolidayList =null;
While value types have default values and can not be null, they also need to be explicitly initialized in order to be used. You can think of these two rules as side by side rules.
Value types can not be null โ the compiler guarantees that.
If you ask how, the error message you got is the answer. Once you call their constructors, they got initialized with their default values.
int tmpCnt; // Not accepted
int tmpCnt = new Int(); // Default value applied tmpCnt = 0
In c# using .Net, if you create a class with an uninitialized field and without a constructor, then create an instance of the class with the new keyword, .Net sets the value of the field to the "default value". What exactly does that mean? Is there ever a situation where the value would be set to Null?
Like Johnny mentioned in the comments, this table lists the default values for .NET types. The default value of a reference-type field is null.
The default value is defined on a per-type basis. In general, any reference type will default to null.
You can find a full list of default values based on the type in the documentation.
Furthermore, you can find out empirically by explicitly using the default keyword and checking (e.g. in the debugger) what value was returned:
var x = default(string);
var y = default(int);
A primitive C# value type, for example int is a struct. So, why is int not initialized? There supposed to be default constructor, I think. On the other hand, a custom struct is ok.
In the following code
struct STRCT { }
class Program
{
static void Main(string[] args)
{
STRCT strct;
strct.Equals(8);
strct.GetHashCode();
strct.GetType();
strct.ToString();
int i;
i.Equals(8);
i.GetHashCode();
i.GetType();
i.ToString();
}
}
while first 5 lines of code are ok from the C# compiler view, next 5 lines of code generates compile error:
use of unassigned local variable
Please, explain why? From my point of view both types are structs and shall have the same behavior.
It's a pathological extreme of the rules of Definite Assignment. Specifically:
A struct-type variable is considered definitely assigned if each of its instance variables is considered definitely assigned.
In this case (STRCT strct), the set of instance variables is empty, and so it is true that they've all been definitely assigned.
This is because, unlike the int, your STRCT doesn't contain any fields and therefore doesn't contain anything that could be "unassigned".
Try changing it to:
struct STRCT
{
public int X;
}
Then you'll get the same compile error:
Error CS0165 Use of unassigned local variable
'strct' ConsoleApplication1 D:\Test\CS6\ConsoleApplication1\Program.cs 15
The C# language specification has explicit rules for "Definite Assignment" in section 5.3:
At a given location in the executable code of a function member, a variable is said to be definitely assigned if the compiler can prove, by a particular static flow analysis (ยง5.3.3), that the variable has been automatically initialized or has been the target of at least one assignment
And then:
A struct-type variable is considered definitely assigned if each of its instance variables is considered definitely assigned.
So from that last rule, if a struct has no instance variables (i.e. fields) then it is considered to be "definitely assigned", and therefore no compile error will be omitted.
It's class Members that are automatically initialized - so if your int was a field or a property in a class, you'd fine.
However, local variables to a method are not initialized and expect you to give them a value.
Your struct variable works ok for the time being, since it contains no members of its own. Once you add
struct STRCT
{
private int a;
}
you'll get an error for it, too.
Structs are value types
Unlike reference types, a value type cannot contain the null value. However, the nullable types feature does allow for value types to be assigned to null.
Each value type has an implicit default constructor that initializes the default value of that type. For information about default values of value types
See - https://msdn.microsoft.com/en-us/library/s1ax56ch.aspx
My code is the following
int tmpCnt;
if (name == "Dude")
tmpCnt++;
Why is there an error "Use of unassigned local variable tmpCnt"?
I know I didn't explicitly initialize it, but due to Default Value Table a value type is initialized with 0 anyway. The reference also reminds me:
Remember that using uninitialized variables in C# is not allowed.
But why do I have to do it explicitly if it's already done by default? Wouldn't it gain performance if I wouldn't have to do it?
Local variables aren't initialized. You have to manually initialize them.
Members are initialized, for example:
public class X
{
private int _tmpCnt; // This WILL initialize to zero
...
}
But local variables are not:
public static void SomeMethod()
{
int tmpCnt; // This is not initialized and must be assigned before used.
...
}
So your code must be:
int tmpCnt = 0;
if (name == "Dude")
tmpCnt++;
So the long and the short of it is, members are initialized, locals are not. That is why you get the compiler error.
Default assignments apply to class members, but not to local variables. As Eric Lippert explained it in this answer, Microsoft could have initialized locals by default, but they choose not to do it because using an unassigned local is almost certainly a bug.
The following categories of variables are classified as initially unassigned:
Instance variables of initially unassigned struct variables.
Output parameters, including the this variable of struct instance constructors.
Local variables , except those declared in a catch clause or a foreach statement.
The following categories of variables are classified as initially assigned:
Static variables.
Instance variables of class instances.
Instance variables of initially assigned struct variables.
Array elements.
Value parameters.
Reference parameters.
Variables declared in a catch clause or a foreach statement.
Local variables don't have a default value.
They have to be definitely assigned before you use them. It reduces the chance of using a variable you think you've given a sensible value to, when actually it's got some default value.
The default value table only applies to initializing a variable.
Per the linked page, the following two methods of initialization are equivalent...
int x = 0;
int x = new int();
In your code, you merely defined the variable, but never initialized the object.
A very dummy mistake, but you can get this with a class too if you didn't instantiate it.
BankAccount account;
account.addMoney(5);
The above will produce the same error whereas:
class BankAccount
{
int balance = 0;
public void addMoney(int amount)
{
balance += amount;
}
}
Do the following to eliminate the error:
BankAccount account = new BankAccount();
account.addMoney(5);
Local variables are not automatically initialized. That only happens with instance-level variables.
You need to explicitly initialize local variables if you want them to be initialized. In this case, (as the linked documentation explains) either by setting the value of 0 or using the new operator.
The code you've shown does indeed attempt to use the value of the variable tmpCnt before it is initialized to anything, and the compiler rightly warns about it.
See this thread concerning uninitialized bools, but it should answer your question.
Local variables are not initialized unless you call their constructors (new) or assign them a value.
IEnumerable<DateTime?> _getCurrentHolidayList; //this will not initailize
Assign value(_getCurrentHolidayList) inside the loop
foreach (HolidaySummaryList _holidayItem in _holidayDetailsList)
{
if (_holidayItem.CountryId == Countryid)
_getCurrentHolidayList = _holidayItem.Holiday;
}
After your are passing the local varibale to another method like below.
It throw error(use of unassigned variable). eventhough nullable mentioned in time of decalration.
var cancelRescheduleCondition = GetHolidayDays(_item.ServiceDateFrom, _getCurrentHolidayList);
if you mentioned like below, It will not throw any error.
IEnumerable<DateTime?> _getCurrentHolidayList =null;
While value types have default values and can not be null, they also need to be explicitly initialized in order to be used. You can think of these two rules as side by side rules.
Value types can not be null โ the compiler guarantees that.
If you ask how, the error message you got is the answer. Once you call their constructors, they got initialized with their default values.
int tmpCnt; // Not accepted
int tmpCnt = new Int(); // Default value applied tmpCnt = 0