After reading Meanings of declaring, instantiating, initializing and assigning an object it talks about what initializing a variable means. But it doesn't explain what "initializing" an instance of a class means.
public class Test
{
public static void Main()
{
Person person1 = new Person();
}
}
public class Person
{
// body
}
What does it mean to initialize an instance of a class?
Yeah, I don't like the "initialize" of the linked answer so much either, because it really only talks about giving a value to a single variable and doesn't really draw any distinctions between instantiation and assignment (the same lines of code are found in all of them) so for me it's a bit vague. We do have more specific processes (especially these days of modern c# syntax) when we talk about initialization
Initialize usually means "to give a created instance some initial values". Your class Person has nothing to initialize, so you could say that just by making it anew(instantiating) you've also done all the initialization possible and it's ready for use
Let's have something we can set values on
public class Person{
public string Name {get;set;}
public string Address {get;set;}
public Person(string name){
if(name == null) throw new ArgumentNullException(nameof(name));
Name = name;
}
}
Initializing as part of construction:
p = new Person("John");
Constructors force us to supply values and are used to ensure a developer gives a class the minimum set of data it needs to work.. a Person must have a name. Address is optional. We have created a person with the name initialized to John
Initializing post construction
You can give an instance additional (optional) values after you construct it, either like
p = new Person("Bill");
p.Address = "1 Microsoft Way";
Or
p = new Person("Bill"){
Address = "1 Microsoft Way"
}
Which is a syntactic sugar the compiler unrolls to something like the first. We refer to everything in the { } brackets of the second example as "an object initializer". An important distinction here though is that the first form (p.Address=...) is not considered to be initialization by the compiler. If you made the address property like:
public string Address {get;init;}
Then it can only be set in a constructor or in an object initializer, which is the latter form above. The p.Address=... form would result in a compiler error if the property were declared with init
Props set just after construction are part of the initialization process (as an English/linguistic thing) though I wouldn't call it init if it was any further down the line, such as
p = new Person("Sam");
string addr = Console.ReadLine();
p.Address = addr; //not initialization
You might find cases where people talk about initialization in the sense for "the first time a variable or property is given a value" but that's also more a linguistic/English thing than a c# thing
The compiler knows how to perform other initialization, so we also call things like this "an initializer":
string[] x = new string[] {"a","b","c"};
The process of giving the array those 3 values is initialization, and the compiler will even take the type of the first argument and use it to make the array type, so an array can be type declared and ignited from the data:
var x = new[] {"a","b","c"};
Related
This question already has answers here:
.NET object creation, whats faster?
(4 answers)
Closed 6 years ago.
Given the following example, is one objectively better/faster/safer than the other? Should object literal instantiation be a best practice where it is practical?
Where is this inappropriate?
class Person
{
public string name;
public int age;
}
void MakePeople()
{
Person myPerson = new Person();
myPerson.name = "Steve";
myPerson.age = 21;
Person literalPerson = new Person { name = "John", age = 22 };
}
No, it isn't faster or slower. It is the same.
The compiler translates object initializers to a constructor call followed by setting those properties.
Person literalPerson = new Person { name = "John", age = 22 };
Turns to:
Person myPerson = new Person();
myPerson.name = "John";
myPerson.age = 22;
You should use what is more readable and what you have agreed on with your team.
Either is appropriate. It depends on what you need to do to set properties. For example, I would avoid literal instantiation in cases where some logic is needed to arrive at a property value:
Person myPerson = new Person();
myPerson.SomeProperty = if IsNewPerson ? GetPropertyFromDatabase() : GetDefaultProperty();
Edit:
One advantage to using literal object initialization in Visual Studio is that Intellisense will prompt for properties, showing only those which have not already been declared. (I've ran into code where a value was redundantly assigned when setting properties.)
If you take a look at the IL that is generated, I'm pretty sure you'll find that they are identical. Using object initializers is just a compiler shortcut.
I don't think speed should be what drives this decision. There is probably very little difference between the speed of either method.
I think code readability should be the prime factor in which way you go. Using that criteria, I think they are very close and it comes down to personal preference or whatever your team decides on. However, I think in the case of a object with requires many properties to be set, explicitly calling setters is a little more readable.
I always thought that a method parameter with a class type is passed as a reference parameter by default. Apparently that is not always the case. Consider these unit tests in C# (using MSTest).
[TestClass]
public class Sandbox
{
private class TestRefClass
{
public int TestInt { get; set; }
}
private void TestDefaultMethod(TestRefClass testClass)
{
testClass.TestInt = 1;
}
private void TestAssignmentMethod(TestRefClass testClass)
{
testClass = new TestRefClass() { TestInt = 1 };
}
private void TestAssignmentRefMethod(ref TestRefClass testClass)
{
testClass = new TestRefClass() { TestInt = 1 };
}
[TestMethod]
public void DefaultTest()
{
var testObj = new TestRefClass() { TestInt = 0 };
TestDefaultMethod(testObj);
Assert.IsTrue(testObj.TestInt == 1);
}
[TestMethod]
public void AssignmentTest()
{
var testObj = new TestRefClass() { TestInt = 0 };
TestAssignmentMethod(testObj);
Assert.IsTrue(testObj.TestInt == 1);
}
[TestMethod]
public void AssignmentRefTest()
{
var testObj = new TestRefClass() { TestInt = 0 };
TestAssignmentRefMethod(ref testObj);
Assert.IsTrue(testObj.TestInt == 1);
}
}
The results are that AssignmentTest() fails and the other two test methods pass. I assume the issue is that assigning a new instance to the testClass parameter breaks the parameter reference, but somehow explicitly adding the ref keyword fixes this.
Can anyone give a good, detailed explanation of whats going on here? I'm mainly just trying to expand my knowledge of C#; I don't have any specific scenario I'm trying to solve...
The thing that is nearly always forgotten is that a class isn't passed by reference, the reference to the class is passed by value.
This is important. Instead of copying the entire class (pass by value in the stereotypical sense), the reference to that class (I'm trying to avoid saying "pointer") is copied. This is 4 or 8 bytes; much more palatable than copying the whole class and in effect means the class is passed "by reference".
At this point, the method has it's own copy of the reference to the class. Assignment to that reference is scoped within the method (the method re-assigned only its own copy of the reference).
Dereferencing that reference (as in, talking to class members) would work as you'd expect: you'd see the underlying class unless you change it to look at a new instance (which is what you do in your failing test).
Using the ref keyword is effectively passing the reference itself by reference (pointer to a pointer sort of thing).
As always, Jon Skeet has provided a very well written overview:
http://www.yoda.arachsys.com/csharp/parameters.html
Pay attention to the "Reference parameters" part:
Reference parameters don't pass the values of the variables used in
the function member invocation - they use the variables themselves.
If the method assigns something to a ref reference, then the caller's copy is also affected (as you have observed) because they are looking at the same reference to an instance in memory (as opposed to each having their own copy).
The default convention for parameters in C# is pass by value. This is true whether the parameter is a class or struct. In the class case just the reference is passed by value while in the struct case a shallow copy of the entire object is passed.
When you enter the TestAssignmentMethod there are 2 references to a single object: testObj which lives in AssignmentTest and testClass which lives in TestAssignmentMethod. If you were to mutate the actual object via testClass or testObj it would be visible to both references since they both point to the same object. In the first line though you execute
testClass = new TestRefClass() { TestInt = 1 }
This creates a new object and points testClass to it. This doesn't alter where the testObj reference points in any way because testClass is an independent copy. There are now 2 objects and 2 references which each reference pointing to a different object instance.
If you want pass by reference semantics you need to use a ref parameter.
My 2 cents
When a class is passed to a method, a copy of its memory space address is being sent (a direction to your house is being sent). So any operation on that address will affect the house but will not change the address itself. (This is default).
Passing a class (object) by reference has an effect of passing its actual address instead of a copy of an address. That means if you assign a new object to an argument passed by reference it will change the actual address (similar to relocation). :D
This is how I see it.
The AssignmentTest uses TestAssignmentMethod which only changes the object reference passed by value.
So the object itself is passed by reference but the reference to the object is passed by value. so when you do:
testClass = new TestRefClass() { TestInt = 1 };
You are changing the local copied reference passed to the method not the reference you have in the test.
So here:
[TestMethod]
public void AssignmentTest()
{
var testObj = new TestRefClass() { TestInt = 0 };
TestAssignmentMethod(testObj);
Assert.IsTrue(testObj.TestInt == 1);
}
testObj is a reference variable. When you pass it to TestAssignmentMethod(testObj);, the refernce is passed by value. so when you change it in the method, original reference still points to the same object.
There are lot's of subtleties missed in the posted answers here that will create unexpected results and confuse new C# developers. There are actually two ways to process a reference passed by value in C# methods.
All methods in C# pass arguments in BY VALUE by default unless you use the ref, in, or out keywords. Passing a REFERENCE BY VALUE means a COPY of the MEMORY ADDRESS of the object used by the outside reference is passed in and assigned to the method parameter. The original outside variable address is not passed in nor the original object in memory, just the memory address to the object.
Both variables now point to the same object in memory.
This copy of the address to the object in memory is the VALUE for pass by value for all reference types. That means the original reference variable that points to the object address remains the same, and a new copy of that memory address is assigned to a new variable in the method parameter. They BOTH point to the same object. That means if either change properties on the object, it will affect the original object and will be seen by both variables.
This seems to act like a PASS BY REFERENCE, but it is not. That is what confuses many developers.
But this means some "weird" and unexpected things can happen passing a reference by value in methods if you are not careful. It means your method variable can connect to the same object and change the properties and fields of the original shared object ...BUT... as soon as you reassign the method variable to a new instance of the same type of object, it loses a connection to the original instance and no longer affects the original object used by the outside reference.
You might assume the method has assigned a fresh object to the outside reference variable, but you have not! Changing that new object's properties in the method no longer affect the outside reference. So BE CAREFUL!
Let's test this weirdness in C#:
// First, create my cat class. I can change its name
// to anything I want. But instead, I want it to have
// a special name assigned by the next class via a method.
class MyCat
{
public string Name { get; set; }
}
// This special class will assign a popular name to me cat.
class CatNames
{
public enum PopularNames {
Felix,
Fluffy
}
public void ChangeName(MyCat c)
{
PopularNames p = PopularNames.Felix;
c.Name = p.ToString();
}
public void ChangeNameAndCat(MyCat c)
{
PopularNames p = PopularNames.Fluffy;
MyCat d = new MyCat();
d.Name = p.ToString();
c = d;
// Note: In this case, you might want to return the new "MyCat"
// object and its name to the caller.
}
}
// Testing passing by value and how references are passed...
CatNames catnamechanger = new CatNames();
// I created two cats with the same name so you can see
// what names actually changed below.
MyCat cat1 = new MyCat();
cat1.Name = "Bubba";
MyCat cat2 = new MyCat();
cat2.Name = "Bubba";
catnamechanger.ChangeName(cat1);
catnamechanger.ChangeNameAndCat(cat2);
Console.WriteLine("My Cat1's Name is: " + cat1.Name);
Console.WriteLine("My Cat2's Name is: " + cat2.Name);
// ============== OUTPUT ==================
// My Cat1's Name is: Felix
// My Cat2's Name is: Bubba <<< OOPS! My cat name kept the original
RESULTS
Notice the first cat had its name changed on the original object, but the second cat kept its original name, "Bubba", as a new cat was assigned to the method variable. It lost connection to the original object. The reason is, passing a reference by value still allows you to affect properties of the passed in address to the original object. But as soon as you change where the method variable points, that reference is lost.
Ok so I have the code below, technically all it does is read the db.txt file line by line and then its suppose to split the line 0 into an array called password.
private string[] lines = System.IO.File.ReadAllLines(#"U:\Final Projects\Bank\ATM\db.txt");
private string[] password = lines[0].Split(' ');
but I get the error:
A field initializer cannot reference the non-static field, method, or property
Have a think about what the above means and how you want to populate those variables. You'd need to first construct the class they are a member of, and then hope the lines of code get executed in the order you want them to, and that they don't throw an exception.
The compiler is effectively telling you this isn't the right way to do things.
A better way is to simply write a function to do what you want:
private string[] PasswordLines(){
string[] lines = System.IO.File.ReadAllLines(#"U:\Final Projects\Bank\ATM\db.txt");
return lines[0].Split(" ");
}
You can then call this from anywhere you wanted to; for example:
public class MyClass()
{
private string[] Lines
{
get { return PasswordLines(); }
}
private string[] PasswordLines(){
string[] lines = System.IO.File.ReadAllLines(#"U:\Final Projects\Bank\ATM\db.txt");
return lines[0].Split(" ");
}
}
C# does not guarantees any specific order of execution when it comes to filed initialization.
For instance these two lines of code will produce undefined results:
private int a = b + 1;
private int b = a + 1;
in theory, the two possible outcomes are a=1,b=2 or a=2,b=1, but in fact it's even worst. We don't even know if a and b are initialized to their default values yet (0 in case of int), so it can be anything (just like a reference to uninitialized object).
To avoid this impossible-to-solve scenario, the compiler demands that all field initializations will be "run-time constants" (return the same value every time, whenever they are executed and independent of any other non "run-time constant" variables).
Just use the constructor when you initialize compound fields and life will be sweet again.
Exactly what is says! Those are (instance) field initializers, and cannot reference each other. Move the code to the constructor instead, or make them method variables instead of fields.
The error is self explanatory.
you can't do this because lines and password both are field variables and you can't assign
one of them value to other(if it's a static then you can).
i hope you are using this code inside a class so until unless an object is not create their no such real existence of these field variables so you can't assign them to each other.
Recently I saw a person heavily using var and default keywords for declaration of variables (and for every declaration), something like this:
var employee = default(Employee); //Employee is a class
var errorInfo = default(ErrorInfo); //ErrorInfo is struct; Blank is default value
var salary = default(Double);
var isManager = default(Boolean?);
instead of using:
Employee employee = null; //Employee is a class
ErrorInfo errorInfo = Blank; //ErrorInfo is struct; Blank is default value
Double salary = 0.0;
Boolean? isManager = null;
or, instead of using even:
Employee employee; //Employee is a class
ErrorInfo errorInfo; //ErrorInfo is struct; Blank is default value
Double salary;
Boolean? isManager;
Now using var and default for declaration for every variable is something i am not accustomed to.
Want to know:
- If this is a recommended practice?
- Your views and preference?
PS:
- Have gone through Use of var keyword in C#, Use of "var" type in variable declaration and https://stackoverflow.com/questions/633474/c-do-you-use-var, however, think that this question although related is slightly different as it is solely around declaration/initialization and not around assignment.
- I understand the difference between snipped 2 and snippet 3. However, question is more around snippet 1.
- If you strongly feel that this question belongs to programmers stackexchange feel free to move.
I'm not going to say anything about "var" there have been comments and discussions about this in the past (sufficiently so ;-)
Concerning "default()" I would not use this to initialize a known type, but rather only in generics. There it helps to transparently handle value types or reference types by allowing you to provide a default (return) value or can be used in comparisons.
Well, the default keyword isn't the most used keyword I think, and in my opinion it serves its purpose best in terms of Generics, like so:
public class Foo<T>{
private T _instance;
public Foo<T>(){
_instance = default(T);
}
}
in order to get a new default instance of T.
There are really no reasons to use it like scenario 1 in your post.
Using var however is a different question, and many view this as a matter of readability. I default to var when I write code simply because I find it easier to read:
var me = new Person();
It seems a bit redundant in terms of readability to do
Person me = new Person();
Another case I recommend var is if something changes. Consider the following example:
public decimal Calculate(decimal one, decimal two){
return one + two;
}
And somewhere else in your code:
decimal d = Calculate(1M, 2M);
If you for some reason change the return type of Calculate to, say, double you need to change all the places where you strongly defined the variable.
If you instead do
var d = Calculate(1M, 2M)
you don't have to worry about this. The Double/Decimal example is a bit simple, but in terms of refactoring and interfacing out classes, I've found this very useful.
I think this is bad practice which will prevent the compiler (and 3rd party tools) from catching bugs related to failure to initialize a variable. Generally I try to keep declaration and assignment as close to each other as possible. Assigning values that aren't intended to be used to variables can potentially introduce subtle bugs that are difficult to catch. Normally I'd either:
SomeType variable1; //want to store something that will be out of scope later
using(blah)
{
//...
variable1=blah;
}
//use variable1 here
or assign required value immediately:
SomeType variable2 = new SomeType();
//use variable2 immediately
or (for me, more frequently nowdays)
var variable2 = new SomeType();
assigning null/placeholder values is mainly pointless.
I use var for assignment. However I always declare instances using the class. I generally also instantiate them at the time to avoid unexpected NullReferenceExceptions
The code is ok.
Just make sure that you don't copy this technique to initialize enums where 0 is not default value or flagged enumerations.
[Flags]
public enum MyFlags
{
Test = 1,
Test2 = 2
}
MyFlags flags = default(MyFlags);
Console.WriteLine(flags); // oops
I'm getting confused with what happens on the stack and heap in respect to value type properties in classes.
My understanding so far:
When you create a class with a structure (value type) like this:
class Foo
{
private Bar _BarStruct;
public Bar BarStruct
{
get {return _BarStruct; }
set {_BarStruct = value; }
}
}
private struct Bar
{
public int Number;
Bar()
{
Number = 1;
}
Bar(int i)
{
Number = i;
}
}
If you create a class instance like so:
Foo fooObj = new Foo();
The stack and heap will look like this:
...where the Bar structure is embeded in the Foo class in the heap. This makes sense to me, but I start to loose it when we consider modifying the Number integer in the BarStruct class, within the Foo Object. For example:
Foo fooObj = new Foo();
fooObj.BarStruct.Number = 1;
As I understand, this should be returning a copy of BarStruct to live on the stack, which means that any changes of a member of BarStruct would not be carried through to the object, which is why the last line above gives an error.
Is this right so far?
If so, my question is, how come an assignment such as this:
fooObj.BarStruct = new Bar(2);
...is valid and changes the heap value? Surely this is just changing the value on the stack?? Also, (by and by) I find it so confusing that you are able to use new on a value type. To me, new is for allocatting on the heap (as per C++) and feels unnatural to be doing this for items on the stack.
So just to re-iterate the question, Am I correct in my assumption of what happens when a property containing a structure is called and why can you assign a new structure to a copy and yet it still changes the reference on the heap?
Really hope this all make sense.
Yell if you need clarification!
Ta,
Andy.
Looking at this assignment:
fooObj.BarStruct = new Bar(2);
The assignment isn't changing the value on the stack - it's calling the setter for the property.
In other words, whereas your first assignment is equivalent to:
fooObj.get_BarStruct().Number = 1; // Bad
the second is equivalent to:
fooObj.set_BarStruct(new Bar(2));
Does that help?
Note that the problematic assignment becomes a non-issue if you make your value type immutable to start with - which helps in general, in fact. Mutable value types are a really bad idea in C#; you can get into no end of trouble with them.
In terms of your expectations of "new" - try not to think in C++, basically. C# isn't C++, and various things (destructors, generics, behaviour during construction) will confuse you if you try to effectively write C++ in C#. A "new" statement creates a new instance of a type, whether that's a value type or a reference type.