Do anonymous initializes override defaults, or are they run after? - c#

If I have a default initializer set, and a define an anonymous one when I create my object. Is the default skipped, or just run before? The reason I want to know is because in the case below, if they are run after, the List object created in the default will be discarded immediately, thus creating unnecessary garbage.
class ArrangedPanel : RectElement
{
public List<RectElement> arrangedChildren = new List<RectElement>();
public int Padding = 2;
}
//Somewhere else
new ArrangedPanel()
{
Padding = 5,
arrangedChildren = new List<RectElement>()
{
new ButtonToggle(),
new ButtonToggle()
}
}

In your example code the Padding = 2 occurs before Padding = 5.
You are unnecessarily creating a List<RectElement>, but I'd challenge you to create a scenario where such unnecessary allocations cause any appreciable performance hit.

arrangedChildren will be set to the last instance you create
for example:
arrangedChildren = new List<RectElement>();
arrangedChildren = new List<RectElement>()
{
new ButtonToggle(),
new ButtonToggle()
}
the arrangedChildren will point to the second list.
If no other object references to the first one it will disapair (GC).
But if some 1 would keep a reference to the first instance it will stay alive and you could have duplicates or two differents lists where you are working on.
This could cause some problems

From the C# Specification, section 17.4.5.2
The instance field variable initializers of a class correspond to a
sequence of assignments that are executed immediately upon entry to
any one of the instance constructors (§17.10.2) of that class. The
variable initializers are executed in the textual order in which they
appear in the class declaration. The class instance creation and
initialization process is described further in §17.10.
Thus the initializations in the body class declaration will be performed first, followed by the initializations in the constructor. This can be observed directly by viewing the IL output.

Related

What does "initializing an instance of a class" mean?

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"};

Best way to keep track of objects when writing a debugger [duplicate]

Is there a way of getting a unique identifier of an instance?
GetHashCode() is the same for the two references pointing to the same instance. However, two different instances can (quite easily) get the same hash code:
Hashtable hashCodesSeen = new Hashtable();
LinkedList<object> l = new LinkedList<object>();
int n = 0;
while (true)
{
object o = new object();
// Remember objects so that they don't get collected.
// This does not make any difference though :(
l.AddFirst(o);
int hashCode = o.GetHashCode();
n++;
if (hashCodesSeen.ContainsKey(hashCode))
{
// Same hashCode seen twice for DIFFERENT objects (n is as low as 5322).
Console.WriteLine("Hashcode seen twice: " + n + " (" + hashCode + ")");
break;
}
hashCodesSeen.Add(hashCode, null);
}
I'm writing a debugging addin, and I need to get some kind of ID for a reference which is unique during the run of the program.
I already managed to get internal ADDRESS of the instance, which is unique until the garbage collector (GC) compacts the heap (= moves the objects = changes the addresses).
Stack Overflow question Default implementation for Object.GetHashCode() might be related.
The objects are not under my control as I am accessing objects in a program being debugged using the debugger API. If I was in control of the objects, adding my own unique identifiers would be trivial.
I wanted the unique ID for building a hashtable ID -> object, to be able to lookup already seen objects. For now I solved it like this:
Build a hashtable: 'hashCode' -> (list of objects with hash code == 'hashCode')
Find if object seen(o) {
candidates = hashtable[o.GetHashCode()] // Objects with the same hashCode.
If no candidates, the object is new
If some candidates, compare their addresses to o.Address
If no address is equal (the hash code was just a coincidence) -> o is new
If some address equal, o already seen
}
.NET 4 and later only
Good news, everyone!
The perfect tool for this job is built in .NET 4 and it's called ConditionalWeakTable<TKey, TValue>. This class:
can be used to associate arbitrary data with managed object instances much like a dictionary (although it is not a dictionary)
does not depend on memory addresses, so is immune to the GC compacting the heap
does not keep objects alive just because they have been entered as keys into the table, so it can be used without making every object in your process live forever
uses reference equality to determine object identity; moveover, class authors cannot modify this behavior so it can be used consistently on objects of any type
can be populated on the fly, so does not require that you inject code inside object constructors
Checked out the ObjectIDGenerator class? This does what you're attempting to do, and what Marc Gravell describes.
The ObjectIDGenerator keeps track of previously identified objects. When you ask for the ID of an object, the ObjectIDGenerator knows whether to return the existing ID, or generate and remember a new ID.
The IDs are unique for the life of the ObjectIDGenerator instance. Generally, a ObjectIDGenerator life lasts as long as the Formatter that created it. Object IDs have meaning only within a given serialized stream, and are used for tracking which objects have references to others within the serialized object graph.
Using a hash table, the ObjectIDGenerator retains which ID is assigned to which object. The object references, which uniquely identify each object, are addresses in the runtime garbage-collected heap. Object reference values can change during serialization, but the table is updated automatically so the information is correct.
Object IDs are 64-bit numbers. Allocation starts from one, so zero is never a valid object ID. A formatter can choose a zero value to represent an object reference whose value is a null reference (Nothing in Visual Basic).
The reference is the unique identifier for the object. I don't know of any way of converting this into anything like a string etc. The value of the reference will change during compaction (as you've seen), but every previous value A will be changed to value B, so as far as safe code is concerned it's still a unique ID.
If the objects involved are under your control, you could create a mapping using weak references (to avoid preventing garbage collection) from a reference to an ID of your choosing (GUID, integer, whatever). That would add a certain amount of overhead and complexity, however.
RuntimeHelpers.GetHashCode() may help (MSDN).
You can develop your own thing in a second. For instance:
class Program
{
static void Main(string[] args)
{
var a = new object();
var b = new object();
Console.WriteLine("", a.GetId(), b.GetId());
}
}
public static class MyExtensions
{
//this dictionary should use weak key references
static Dictionary<object, int> d = new Dictionary<object,int>();
static int gid = 0;
public static int GetId(this object o)
{
if (d.ContainsKey(o)) return d[o];
return d[o] = gid++;
}
}
You can choose what you will like to have as unique ID on your own, for instance, System.Guid.NewGuid() or simply integer for fastest access.
How about this method:
Set a field in the first object to a new value. If the same field in the second object has the same value, it's probably the same instance. Otherwise, exit as different.
Now set the field in the first object to a different new value. If the same field in the second object has changed to the different value, it's definitely the same instance.
Don't forget to set field in the first object back to it's original value on exit.
Problems?
It is possible to make a unique object identifier in Visual Studio: In the watch window, right-click the object variable and choose Make Object ID from the context menu.
Unfortunately, this is a manual step, and I don't believe the identifier can be accessed via code.
You would have to assign such an identifier yourself, manually - either inside the instance, or externally.
For records related to a database, the primary key may be useful (but you can still get duplicates). Alternatively, either use a Guid, or keep your own counter, allocating using Interlocked.Increment (and make it large enough that it isn't likely to overflow).
I know that this has been answered, but it's at least useful to note that you can use:
http://msdn.microsoft.com/en-us/library/system.object.referenceequals.aspx
Which will not give you a "unique id" directly, but combined with WeakReferences (and a hashset?) could give you a pretty easy way of tracking various instances.
If you are writing a module in your own code for a specific usage, majkinetor's method MIGHT have worked. But there are some problems.
First, the official document does NOT guarantee that the GetHashCode() returns an unique identifier (see Object.GetHashCode Method ()):
You should not assume that equal hash codes imply object equality.
Second, assume you have a very small amount of objects so that GetHashCode() will work in most cases, this method can be overridden by some types.
For example, you are using some class C and it overrides GetHashCode() to always return 0. Then every object of C will get the same hash code.
Unfortunately, Dictionary, HashTable and some other associative containers will make use this method:
A hash code is a numeric value that is used to insert and identify an object in a hash-based collection such as the Dictionary<TKey, TValue> class, the Hashtable class, or a type derived from the DictionaryBase class. The GetHashCode method provides this hash code for algorithms that need quick checks of object equality.
So, this approach has great limitations.
And even more, what if you want to build a general purpose library?
Not only are you not able to modify the source code of the used classes, but their behavior is also unpredictable.
I appreciate that Jon and Simon have posted their answers, and I will post a code example and a suggestion on performance below.
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Collections.Generic;
namespace ObjectSet
{
public interface IObjectSet
{
/// <summary> check the existence of an object. </summary>
/// <returns> true if object is exist, false otherwise. </returns>
bool IsExist(object obj);
/// <summary> if the object is not in the set, add it in. else do nothing. </summary>
/// <returns> true if successfully added, false otherwise. </returns>
bool Add(object obj);
}
public sealed class ObjectSetUsingConditionalWeakTable : IObjectSet
{
/// <summary> unit test on object set. </summary>
internal static void Main() {
Stopwatch sw = new Stopwatch();
sw.Start();
ObjectSetUsingConditionalWeakTable objSet = new ObjectSetUsingConditionalWeakTable();
for (int i = 0; i < 10000000; ++i) {
object obj = new object();
if (objSet.IsExist(obj)) { Console.WriteLine("bug!!!"); }
if (!objSet.Add(obj)) { Console.WriteLine("bug!!!"); }
if (!objSet.IsExist(obj)) { Console.WriteLine("bug!!!"); }
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
public bool IsExist(object obj) {
return objectSet.TryGetValue(obj, out tryGetValue_out0);
}
public bool Add(object obj) {
if (IsExist(obj)) {
return false;
} else {
objectSet.Add(obj, null);
return true;
}
}
/// <summary> internal representation of the set. (only use the key) </summary>
private ConditionalWeakTable<object, object> objectSet = new ConditionalWeakTable<object, object>();
/// <summary> used to fill the out parameter of ConditionalWeakTable.TryGetValue(). </summary>
private static object tryGetValue_out0 = null;
}
[Obsolete("It will crash if there are too many objects and ObjectSetUsingConditionalWeakTable get a better performance.")]
public sealed class ObjectSetUsingObjectIDGenerator : IObjectSet
{
/// <summary> unit test on object set. </summary>
internal static void Main() {
Stopwatch sw = new Stopwatch();
sw.Start();
ObjectSetUsingObjectIDGenerator objSet = new ObjectSetUsingObjectIDGenerator();
for (int i = 0; i < 10000000; ++i) {
object obj = new object();
if (objSet.IsExist(obj)) { Console.WriteLine("bug!!!"); }
if (!objSet.Add(obj)) { Console.WriteLine("bug!!!"); }
if (!objSet.IsExist(obj)) { Console.WriteLine("bug!!!"); }
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
public bool IsExist(object obj) {
bool firstTime;
idGenerator.HasId(obj, out firstTime);
return !firstTime;
}
public bool Add(object obj) {
bool firstTime;
idGenerator.GetId(obj, out firstTime);
return firstTime;
}
/// <summary> internal representation of the set. </summary>
private ObjectIDGenerator idGenerator = new ObjectIDGenerator();
}
}
In my test, the ObjectIDGenerator will throw an exception to complain that there are too many objects when creating 10,000,000 objects (10x than in the code above) in the for loop.
Also, the benchmark result is that the ConditionalWeakTable implementation is 1.8x faster than the ObjectIDGenerator implementation.
The information I give here is not new, I just added this for completeness.
The idea of this code is quite simple:
Objects need a unique ID, which isn't there by default. Instead, we have to rely on the next best thing, which is RuntimeHelpers.GetHashCode to get us a sort-of unique ID
To check uniqueness, this implies we need to use object.ReferenceEquals
However, we would still like to have a unique ID, so I added a GUID, which is by definition unique.
Because I don't like locking everything if I don't have to, I don't use ConditionalWeakTable.
Combined, that will give you the following code:
public class UniqueIdMapper
{
private class ObjectEqualityComparer : IEqualityComparer<object>
{
public bool Equals(object x, object y)
{
return object.ReferenceEquals(x, y);
}
public int GetHashCode(object obj)
{
return RuntimeHelpers.GetHashCode(obj);
}
}
private Dictionary<object, Guid> dict = new Dictionary<object, Guid>(new ObjectEqualityComparer());
public Guid GetUniqueId(object o)
{
Guid id;
if (!dict.TryGetValue(o, out id))
{
id = Guid.NewGuid();
dict.Add(o, id);
}
return id;
}
}
To use it, create an instance of the UniqueIdMapper and use the GUID's it returns for the objects.
Addendum
So, there's a bit more going on here; let me write a bit down about ConditionalWeakTable.
ConditionalWeakTable does a couple of things. The most important thing is that it doens't care about the garbage collector, that is: the objects that you reference in this table will be collected regardless. If you lookup an object, it basically works the same as the dictionary above.
Curious no? After all, when an object is being collected by the GC, it checks if there are references to the object, and if there are, it collects them. So if there's an object from the ConditionalWeakTable, why will the referenced object be collected then?
ConditionalWeakTable uses a small trick, which some other .NET structures also use: instead of storing a reference to the object, it actually stores an IntPtr. Because that's not a real reference, the object can be collected.
So, at this point there are 2 problems to address. First, objects can be moved on the heap, so what will we use as IntPtr? And second, how do we know that objects have an active reference?
The object can be pinned on the heap, and its real pointer can be stored. When the GC hits the object for removal, it unpins it and collects it. However, that would mean we get a pinned resource, which isn't a good idea if you have a lot of objects (due to memory fragmentation issues). This is probably not how it works.
When the GC moves an object, it calls back, which can then update the references. This might be how it's implemented judging by the external calls in DependentHandle - but I believe it's slightly more sophisticated.
Not the pointer to the object itself, but a pointer in the list of all objects from the GC is stored. The IntPtr is either an index or a pointer in this list. The list only changes when an object changes generations, at which point a simple callback can update the pointers. If you remember how Mark & Sweep works, this makes more sense. There's no pinning, and removal is as it was before. I believe this is how it works in DependentHandle.
This last solution does require that the runtime doesn't re-use the list buckets until they are explicitly freed, and it also requires that all objects are retrieved by a call to the runtime.
If we assume they use this solution, we can also address the second problem. The Mark & Sweep algorithm keeps track of which objects have been collected; as soon as it has been collected, we know at this point. Once the object checks if the object is there, it calls 'Free', which removes the pointer and the list entry. The object is really gone.
One important thing to note at this point is that things go horribly wrong if ConditionalWeakTable is updated in multiple threads and if it isn't thread safe. The result would be a memory leak. This is why all calls in ConditionalWeakTable do a simple 'lock' which ensures this doesn't happen.
Another thing to note is that cleaning up entries has to happen once in a while. While the actual objects will be cleaned up by the GC, the entries are not. This is why ConditionalWeakTable only grows in size. Once it hits a certain limit (determined by collision chance in the hash), it triggers a Resize, which checks if objects have to be cleaned up -- if they do, free is called in the GC process, removing the IntPtr handle.
I believe this is also why DependentHandle is not exposed directly - you don't want to mess with things and get a memory leak as a result. The next best thing for that is a WeakReference (which also stores an IntPtr instead of an object) - but unfortunately doesn't include the 'dependency' aspect.
What remains is for you to toy around with the mechanics, so that you can see the dependency in action. Be sure to start it multiple times and watch the results:
class DependentObject
{
public class MyKey : IDisposable
{
public MyKey(bool iskey)
{
this.iskey = iskey;
}
private bool disposed = false;
private bool iskey;
public void Dispose()
{
if (!disposed)
{
disposed = true;
Console.WriteLine("Cleanup {0}", iskey);
}
}
~MyKey()
{
Dispose();
}
}
static void Main(string[] args)
{
var dep = new MyKey(true); // also try passing this to cwt.Add
ConditionalWeakTable<MyKey, MyKey> cwt = new ConditionalWeakTable<MyKey, MyKey>();
cwt.Add(new MyKey(true), dep); // try doing this 5 times f.ex.
GC.Collect(GC.MaxGeneration);
GC.WaitForFullGCComplete();
Console.WriteLine("Wait");
Console.ReadLine(); // Put a breakpoint here and inspect cwt to see that the IntPtr is still there
}

I need to reference a variable from a non static class in a non static class constructor. [c#]

I'm trying to make a solar system with natural satellites. Currently I'm drawing a planets relative to a static "Sun" class object, but i wold like to make the class use a position of another planet object and draw relative to that planet. To do that i need to extract the x and y position of that planet object.
This is the class constructor of a class i use for drawing planets.
Nebesko_Telo merkur = new Nebesko_Telo(Sun.x, Sun.y, 4, 12, 4.090909090909091,
1, 255, 255, 255);
// A field initializer cannot reference the non-static field, method,
// or property 'Form1.merkur'.
Nebesko_Telo venera = new Nebesko_Telo(merkur.x, merkur.y, 1, 23, 1.5, 1, 176, 108, 32);
This is the class constructor.
public Nebesko_Telo(doubl _rel_tel_x, double _rel_tel_y, double _r, double _or,
double _Fi_mult, double _tilt_plant_nat, int _re, int_gr, int _bl) {
r = _r;
or = _or;
Fi_mult = _Fi_mult;
re = _re;
gr = _gr;
bl = _bl;
tilt_planet_nat = _tilt_planet_nat;
rel_tel_x = _rel_tel_x;
rel_tel_y = _rel_tel_y;
}
The x and y position constantly update with every tick so i need it constantly update it :^/.
It is illegal to use this in any way in a field initializer. merkur in your initializer of venera is actually this.merkur, so it counts.
C# prevents this because that technique is a common source of bugs. Field initializers run before the constructor bodies, including the constructor bodies of base class constructors. If C# did not restrict you from accessing this it would be extremely easy to access a property or call a method that was not yet ready to be used.
See https://blogs.msdn.microsoft.com/ericlippert/2008/02/15/why-do-initializers-run-in-the-opposite-order-as-constructors-part-one/ for more details on the order in which constructor initializers run.
What you should do is move all your field initializers into the constructor body. Then you are responsible for ensuring that the statements in the body run in the correct order to do the initialization you want.
The first hit in a simple Google search should solve this problem.
Essentially, your problem is you're using one instance variable (merkur) to initialize another instance variable (venera) in your code.
This is not allowed because there's no guarantee that merkur will be initialzed before venera, so the compiler doesn't like that.
Assuming that merkur.x is the same as Sun.x, you can use that to initialize venera as well.
The compiler won't allow you to initialize one instance field with properties from another. Instead I would recommend initializing your fields within whatever method is executed first (such as the Form.Load event). This will allow you to properly initialize your fields prior to processing any information with them. For example:
Nebesko_Telo merkur = null;
Nebesko_Telo venera = null;
private void Form1_Load(object sender, EventArgs e) {
merkur = new Nebesko_Telo(Sun.x, Sun.y, 4, 12, 4.090909090909091, 1, 255, 255, 255);
if (merkur != null)
venera = new Nebesko_Telo(merkur.x, merkur.y, 1, 23, 1.5, 1, 176, 108, 32);
}
Definitely feel free to reference the articles the other answers have provided, this post should also shed some light on the topic as the accepted answer there provides some good details as to why this issue is an actual issue. To quote in case the link ever dies:
You cannot use an instance variable to initialize another instance variable. Why? Because the compiler can rearrange these - there is no guarantee that reminder will be initialized before defaultReminder, so the above line might throw a NullReferenceException at runtime.
Also feel free to look into the Compiler Error CS0236 reference from Microsoft. It should shed some further light on the topic.
Instance fields cannot be used to initialize other instance fields outside a method. If you are trying to initialize a variable outside a method, consider performing the initialization inside the class constructor. For more information, see Methods.

Passing a class as a ref parameter in C# does not always work as expected. Can anyone explain?

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.

A field initializer cannot reference the non-static field, method, or property

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.

Categories

Resources