Teaching References in C# - c#

In a couple of weeks, I'll be teaching a class of first-year engineers the salient points of references in C# as part of their first-year programming course. Most of them have never programmed before, and had enough trouble learning objects, so teaching references is going to be an uphill battle. I plan to have lots of examples available for the students to go through on their own, but just showing a bunch of examples tends to be pretty overwhelming if the the underlying concept doesn't 'click'.
So I'll put the question out to the SO community: what's the best way you've seen references taught? What made it 'click' for you? Is there any reference-related material that I'm missing?
My tentative lesson plan is:
What is a reference (using an argument like Eric Lippert's)
References and the Garbage Collector
Reference Types and Value Types
Immutable Types
Passing by Reference versus Passing by Value (and all of the subtleties of object references being passed by value)
A handful of nasty examples that produce unexpected results if you don't understand 1-5.

One way that I've heard it explained is to use a cell phone or walkie-talkie. You (the instructor) hold one end and declare that you are an object instance. You stay in one place (ie. the heap) while the students pass the other end (which is on speaker phone if it's a cell phone) around the classroom.
They can interact with you through the "reference" they have to you, but they don't really have "you" in their possession.

Binky! (or # http://cslibrary.stanford.edu/104/)

I like the URL analogy that describes the differences between Reference and Value types. You can pass around a URL as a reference to some content. You can modify that URL without modifying that content. You can also get to the content via the URL to perhaps modify the content.
This is a useful reference:
http://www.yoda.arachsys.com/csharp/parameters.html

Try to explain references with figures, as pure text sometimes don't get through to most people. Many resources and books on the topic, do try to explain through figures as it is difficult to relate allocation through verbal communication alone (this is mostly an issue of attention span for most people).
At least try to point out how objects relate to each other, a simple example would be a simple reference.
Given:
class A {
B b = new B();
}
class B {
int mine = 1;
}
When instantiating class A as object a from some context the following figure will illustrate how it will all look in the heap. The point of the illustration is to show how the different objects relate to each other and have a mental model for how the heap works.
+-A-----+
a: *---->| |
| | +-B--------+
| b: *--+-->| |
| | | mine: 1 |
+-------+ | |
+----------+
Also try to explain the difference between heap and stack allocation. Calling a method with parameters. Simple example would be something like this:
Given the following method:
public void doSomething(B b) {
int doMine = b.mine + 1;
}
When calling doSomething and letting it do it's stuff, at the end doSomething's stack will look something like below. The point showing that objects do not directly reside inside a stack, but it is just referred to an object in the heap and objects are shared through references.
whoever called doSomething *
|
v
+-doSomething-+ +-B--------+
| b: *--------+-->| |
|-------------| | mine: 1 |
| doMine: 2 | +----------+
+-------------+
Another illustrative example would be illustrating an array which is an object, and a multidimensional array contains an array of arrays.

I found this article really useful for explaning parameter passing in C#. The article also does a good job explaining value and reference types in general terms.
It's more of a visual representation which helped me a lot.

Pictures and diagrams.
People form mental images of the concepts they're learning, and a visual representation of references and their relation to their associated objects is a good way to start. Likewise, visualizing object as containing member variables (which includes references to other objects) and member methods, a la UML diagrams, is very helpful.
Later, you can delve into the details of how references and primitive types are actually implemented, if you feel the need to do so. But delay these discussions as long as possible, as people can get bogged down in trying to pair abstract concepts to the representational details, which distracts from learning the abstract concepts.

When I was learning VB6, references actually confused me a bit. Then I tried learning C++, and after dealing with pointers, references made perfect sense to me. Understanding it from a what-is-actually-happening perspective was easier to me than understanding it from an oo-concepts perspective. Maybe you can go over the under-the-hood stuff in your lesson.

I would suggest minimizing one's use of the bare term "reference" altogether, since it can be used in .net to refer to two very different things: the content of class-type storage locations, and parameters passed with a "ref" qualifier. Use the term "object reference" for the former, and "ref parameter" for the latter.
In describing what an "object reference" is, I would suggest using the term "object ID". Object ID's have a few things that make them different from "addresses":
One can't do very many things with object ID's. One can test whether one is blank, check whether two of them are equal, copy one to a storage location of suitable type, or look up the object referred to by one and ask it to do something. Most requests to do something with a class-type value or variable are really requests to do something with the referred-to object. Note that one cannot manipulate an ID of one object in such a way as to get the ID of another, as one can do with addresses.
While the system must have a means of converting object ID's to addresses, there is no guarantee that it will use any particular means of doing so. Nor is there any guarantee that the bit pattern associated with any object ID won't spontaneously change; all that is guaranteed is that if the bit pattern changes, the new pattern will refer to the same object as the old.
The system keeps track of every place that object ID's are stored. As long as any copy of an Object ID exists, that object ID will never refer to anything other than the object instance for which it was created. By contrast, in general, systems that use addresses for things do not track every single place where an address might be copied. It's possible that an object might cease to exist while somebody still has a copy of its address, and some new object might be created with the same address.

Related

C# Object References vs. Objects in a List

I asked a question similar to this one a few days ago: C# Does an array of objects store the pointers of said objects?
Now, what I'm asking is a bit more code related. A brief overview, I'm trying to store many objects into a list and the said objects may be very large (1 ~ 2 GB). From my research, a .NET data structure only has 2 GB max of memory. So my question is, am I able to fit more than 1 or 2 objects into a list?
Scenario: I have a human class and I'm trying to store it in a list.
Are these two lines of code different?
List<Human> humanList = new List<Human>();
Human human = new Human(attr1, attr2, attr3);
humanList.Add(human)
vs.
List<Human> humanList = new List<Human>();
humanList.Add(new Human(attr1, attr2, attr3))
Is the first set of code using a reference to the human object so I'll be able to store more objects in the list? Similarly, is the second set of code trying to store the whole human object into the list?
Your two code samples are equivalent (assuming you aren't doing anything else with the human variable after you create it). The new keyword creates a reference which is stored in the list - you're just creating that reference inline instead of storing it in a variable.
Assuming Human is a class and not a struct, the list will contain references to the objects, not the objects themselves.
The size of a Human object will have less bearing on how many references you can store in the list (overall system memory will likely be more of an issue that the 2GB .NET limit).
Both code examples have the same effect.
Both examples store references to your objects.
You will be able to store many more than 1 or 2 objects in the list.
This gets managed by the .Net CLR and code optimization. Your code would be changed in either scenario to store a reference to the human object. The only difference here is that the first example has a hook to the reference for the local method.

Alias for long lookups

I am working on a project that has nested Lists of classes. hence my code look like this when I want to get a variable.
MainClass.subclass1[element1].subClass2[element2].subClass3[element3].value;
I was wondering how I could get an alias for subClass3 so I can get all the variables in it without having to look in all the subclasses, like this.
subClass3Alias.value
in c++ this would be easy simply have a pointer pointing to it, but C# does not really have pointers.
No need for pointers – types in C# are usually reference types anyway, meaning that you can just copy them and they will refer to the original object (like pointers in C++):
var subclassAlias = MainClass.subclass1[element1].subClass2[element2].subClass3[element3];
Now you can use subclassAlias.value.
A slightly different thing occurs if your type happens to be a value type: in that case, the above will still work – but subclassAlias will be a value copy of the original value, meaning that changes to subclassAlias will not be reflected in the original object.
That said, this looks like suspicious code anyway – normally such deep levels of nesting are a sign of bad design and violate the Law of Demeter.
(Incidentally, in C++ you wouldn’t use pointers either.)

How to properly work with non-primitive ClrInstanceField values using ClrMD?

I've got some really large memory dumps of a managed process that I'm trying to get a lot of statistics from--as well as be able to present an interactive view of--fairly deep object graphs on the heap. Think something comparable to !do <address> with prefer_dml 1 set in WinDbg with SOS, where you can continually click on the properties and see their values, only in a much friendlier UI for comparing many objects.
I've found Microsoft.Diagnostics.Runtime (ClrMD) to be particularly well suited for this task, but I'm having a hard time working with array fields and I'm a little confused about object fields, which I have working a little better.
Array:
If I target an array with an address directly off the heap and use ClrType.GetArrayLength and ClrType.GetArrayElementValue things work fine, but once I'm digging through the fields on another object, I'm not sure what value I'm getting from ClrInstanceField.GetValue when the ClrInstanceField.ElementType is ClrElementType.SZArray (I haven't encountered Array digging around in my object graph yet, but I should like to handle it as well).
Edit: I just decided to use the ClrType for System.UInt64 to dereference the array field (using parent address + offset of the array field to calculate the address where the array pointer is stored), then I can work with it the same as if I got it from EnumerateObjects. I am now having some difficulty with some arrays not supporting the ArrayComponentType property. I have yet to test with arrays of Structs so I am also wondering if that will be a C-style allocation of inline structs, as it is with int[] or if it will be an array of pointers to structs on the heap. Guid[] is one of the types I'm having an issue getting the ArrayComponentType from.
Object: Fixed (logic error)
With a ClrInstanceField that has a Type of ClrElementType.Object I get much better results, but still need a little more. Firstly, after calling GetFieldValue I get back a ulong address(?) which I can use ClrInstanceField.Type.Fields against just fine, so I can see the field names and values of the nested object. That said, I have to account for polymorphism, so I tried using ClrHeap.GetObjectType on the same address and it either returns NULL or something completely incorrect. It seems odd that the address would work in my first use case, but not the second.
String: Fixed (found workaround)
Because my real project already uses DbgEng w/ SOS, I have a different way to easily get the value of strings by address, but it seemed very odd that trying to use ClrInstanceField.GetFieldValue succeeded in returning a string, but with completely inaccurate results (a bunch of strange characters). Maybe I'm doing this wrong?
Edit: I have extracted an abstraction that now runs in LINQPad from my original code. It's a bit long to post here, but it's all here in a gist. It's still a little messy from all the copy/paste/refactor and I'll be cleaning it up further an likely posting the final source on either CodePlex or GitHub after I've got these issues fixed.
The code base is fairly large and specific to a project, but if it's absolutely necessary I may be able to extract out a sample set. That said, all access to the ClrMD objects is fairly simple. I get the initial addresses from SOS commands like !dumpheap -stat (which works fine for the root objects) and then I use ClrHeap.GetTypeByName or ClrHeap.GetObjectType. After that it relies exclusively on ClrType.Fields and ClrInstanceField members Type, ElementType, and GetFieldValue
As an added bonus, I did find a browser friendly version of the XML Docs provided with the NuGet package, though it's the same documentation IntelliSense provides.
It's going to be hard to answer very precisely without seeing what your code looks like, but basically, it goes like this:
The first thing you need to know in order to be able to call GetFieldAddress/GetFieldValue is if the object address you have is a regular pointer or an interior pointer. That is, if it directly points to an object on the heap, or to an interior structure within an actual object (think String vs. Struct field within an actual object).
If you're getting the wrong values out of GetFieldAddress/GetFieldValue, it usually means you're not specifying that you have an interior pointer (or you thought you had one when you didn't).
The second part is understanding what the values mean.
If field.IsPrimitive() is true: GetFieldValue() will get you the actual primitive value (i.e. an Int32, Byte, or whatever)
If field.IsValueClass() is true, then GetFieldAddress() will get you an interior pointer to the structure. Thus, any calls on GetFieldAddress/Value() that you use on that address you need to tell it that it is an interior pointer!
If field.ElementType is a ClrElementType.String, then I seem to remember you need to call GetFieldValue will get you the actual string contents (need to check, but this should be it).
Otherwise, you have an object reference, in which case GetFieldValue() will get you a regular pointer to the new reference object.
Does this make sense?

what is the proper way to share information between Generic Lists

I have a couple of generic lists with completely different types of data.
In my generic lists I have created methods to do all the processing that makes sense from that level - that is I have the member function perform a summary and return a value or set of values. One of my reasoning for basing this calculation in the generic list is that it made reading the code in my opinion easier to read and maintain...but that’s subjective I guess.
Anyways I am at a point that some of the data in list_A needs to be shared with the List in List_B and vice-versa and I am stuck as to what would be the proper way to do this. My first consideration was to give List_B the location of List_A and so on.
or...is there something that I have totally missed is there some pattern that I should be using.
Thanks for any direction you can provide.
EDIT: Perhaps a few more words.
concider that List_A is a list of time collections for various equipment, the list would contain values for events during the day like : amount of time producing (ProductionTime) product 'X' or amount of time that equip was down for an unscheduled event like a breakage or the amount of time that fred the operator spent in the washroom and so on.
Now concider that List_B was a container for a history of equipment components that had been repaired.
In industry there are standard performance indicators like the mean time between failure(MTBF) and so on.
Anyways the definition for MTBF is ProductionTime / Sum of failures.
so...List_B is tasked with determing MTBF for equip_x and in order to do so it needs some information from List_A.
I have housed the calculation for MTBF as a member function in List_B but it still needs som info from List_A...
List_B is tasked with determing MTBF for equip_x
And that is where you start to go wrong I think. List_B should be doing List things, ie storing stuff and producing it when asked.
Calculations should be done in another part of your code (another layer). And then it is just a matter of creating the appropriate Join between List_A and List_B.
Single Responsibility, Coherency and all that.
It sounds like you're looking for something like the "friend" keyword in C++. That is, you'd like one type to be able to access the protected and private members of another type. There's no easy way to do this in C# because the "friend" keyword does not exist. See this related question for more details:
Why does C# not provide the C++ style 'friend' keyword?
Without the "friend" keyword, I think your best option is to define an Interface that provides the functionality you want each type to have and let each define that Interface.

C# to C++ 'Gotchas'

I have been developing a project that I absolutely must develop part-way in C++. I need develop a wrapper and expose some C++ functionality into my C# app. I have been a C# engineer since the near-beginning of .NET, and have had very little experience in C++. It still looks very foreign to me when attempting to understand the syntax.
Is there anything that is going to knock me off my feet that would prevent me from just picking up C++ and going for it?
C++ has so many gotchas that I can't enumerate them all. Do a search for "C# vs C++". A few basic things to know:
In C++:
struct and a class are basically the same thing (Default visibility for a struct is public, it's private for a class).
Both struct and class can be created either on the heap or the stack.
You have to manage the heap yourself. If you create something with "new", you have to delete it manually at some point.
If performance isn't an issue and you have very little data to move around, you can avoid the memory management issue by having everything on the stack and using references (& operator).
Learn to deal with .h and .cpp. Unresolved external can be you worse nightmare.
You shouldn't call a virtual method from a constructor. The compiler will never tell you so I do.
Switch case doesn't enforce "break" and go thru by default.
There is not such a thing as an interface. Instead, you have class with pure virtual methods.
C++ aficionados are dangerous people living in cave and surviving on the fresh blood of C#/java programmers. Talk with them about their favorite language carefully.
Garbage collection!
Remember that everytime you new an object, you must be responsible for calling delete.
There are a lot of differences, but the biggest one I can think of that programmers coming from Java/C# always get wrong, and which they never realize they've got wrong, is C++'s value semantics.
In C#, you're used to using new any time you wish to create an object. And whenever we talk about a class instance, we really mean "a reference to the class instance". Foo x = y doesn't copy the object y, it simply creates another reference to whatever object y references.
In C++, there's a clear distinction between local objects, allocated without new (Foo f or Foo f(x, y), and dynamically allocated ones (Foo* f = new Foo() or Foo* f = new Foo(x, y)). And in C# terms, everything is a value type. Foo x = y actually creates a copy of the Foo object itself.
If you want reference semantics, you can use pointers or references: Foo& x = y creates a reference to the object y. Foo* x = &y creates a pointer to the address at which y is located. And copying a pointer does just that: it creates another pointer, which points to whatever the original pointer pointed to. So this is similar to C#'s reference semantics.
Local objects have automatic storage duration -- that is, a local object is automatically destroyed when it goes out of scope. If it is a class member, then it is destroyed when the owning object is destroyed. If it is a local variable inside a function, it is destroyed when execution leaves the scope in which it was declared.
Dynamically allocated objects are not destroyed until you call delete.
So far, you're probably with me. Newcomers to C++ are taught this pretty soon.
The tricky part is in what this means, how it affects your programming style:
In C++, the default should be to create local objects. Don't allocate with new unless you absolutely have to.
If you do need dynamically allocated data, make it the responsibility of a class. A (very) simplified example:
class IntArrayWrapper {
explicit IntArrayWrapper(int size) : arr(new int[size]) {} // allocate memory in the constructor, and set arr to point to it
~IntArrayWrapper() {delete[] arr; } // deallocate memory in the destructor
int* arr; // hold the pointer to the dynamically allocated array
};
this class can now be created as a local variable, and it will internally do the necessary dynamic allocations. And when it goes out of scope, it'll automatically delete the allocated array again.
So say we needed an array of x integers, instead of doing this:
void foo(int x){
int* arr = new int[x];
... use the array ...
delete[] arr; // if the middle of the function throws an exception, delete will never be called, so technically, we should add a try/catch as well, and also call delete there. Messy and error-prone.
}
you can do this:
void foo(int x){
IntArrayWrapper arr(x);
... use the array ...
// no delete necessary
}
Of course, this use of local variables instead of pointers or references means that objects are copied around quite a bit:
Bar Foo(){
Bar bar;
... do something with bar ...
return bar;
}
in the above, what we return is a copy of the bar object. We could return a pointer or a reference, but as the instance created inside the function goes out of scope and is destroyed the moment the function returns, we couldn't point to that. We could use new to allocate an instance that outlives the function, and return a function to that -- and then we get all the memory management headaches of figuring out whose responsibility it is to delete the object, and when that should happen. That's not a good idea.
Instead, the Bar class should simply be designed so that copying it does what we need. Perhaps it should internally call new to allocate an object that can live as long as we need it to. We could then make copying or assignment "steal" that pointer. Or we could implement some kind of reference-counting scheme where copying the object simply increments a reference counter and copies the pointer -- which should then be deleted not when the individual object is destroyed, but when the last object is destroyed and the reference counter reaches 0.
But often, we can just perform a deep copy, and clone the object in its entirety. If the object includes dynamically allocated memory, we allocate more memory for the copy.
It may sound expensive, but the C++ compiler is good at eliminating unnecessary copies (and is in fact in most cases allowed to eliminate copy operations even if they have side effects).
If you want to avoid copying even more, and you're prepared to put up with a little more clunky usage, you can enable "move semantics" in your classes as well as (or instead of) "copy semantics". It's worth getting into this habit because (a) some objects can't easily be copied, but they can be moved (e.g. a Socket class), (b) it's a pattern established in the standard library and (c) it's getting language support in the next version.
With move semantics, you can use objects as a kind of "transferable" container. It's the contents that move. In the current approach, it's done by calling swap, which swaps the contents of two objects of the same type. When an object goes out of scope, it is destructed, but if you swap its contents into a reference parameter first, the contents escape being destroyed when the scope ends. Therefore, you don't necessarily need to go all the way and use reference counted smart pointers just to allow complex objects to be returned from functions. The clunkiness comes from the fact that you can't really return them - you have to swap them into a reference parameter (somewhat similar to a ref parameter in C#). But the language support in the next version of C++ will address that.
So the biggest C# to C++ gotcha I can think of: don't make pointers the default. Use value semantics, and instead tailor your classes to behave the way you want when they're copied, created and destroyed.
A few months ago, I attempted to write a series of blog posts for people in your situation:
Part 1
Part 2
Part 3
I'm not 100% happy with how they turned out, but you may still find them useful.
And when you feel that you're never going to get a grip on pointers, this post may help.
No run-time checks
One C++ pitfall is the behaviour when you try to do something that might be invalid, but which can only be checked at runtime - for example, dereferencing a pointer that could be null, or accessing an array with an index that might be out of range.
The C# philosophy emphasises correctness; all behaviour should be well-defined and, in cases like this, it performs a run-time check of the preconditions and throws well-defined exceptions if they fail.
The C++ philosophy emphasises efficiency, and the idea that you shouldn't pay for anything you might not need. In cases like this, nothing will be checked for you, so you must either check the preconditions yourself or design your logic so that they must be true. Otherwise, the code will have undefined behaviour, which means it might (more or less) do what you want, it might crash, or it might corrupt completely unrelated data and cause errors that are horrendously difficult to track down.
Just to throw in some others that haven't been mentioned yet by other answers:
const: C# has a limited idea of const. In C++ 'const-correctness' is important. Methods that don't modify their reference parameters should take const-references, eg.
void func(const MyClass& x)
{
// x cannot be modified, and you can't call non-const methods on x
}
Member functions that don't modify the object should be marked const, ie.
int MyClass::GetSomething() const // <-- here
{
// Doesn't modify the instance of the class
return some_member;
}
This might seem unnecessary, but is actually very useful (see the next point on temporaries), and sometimes required, since libraries like the STL are fully const-correct, and you can't cast const things to non-const things (don't use const_cast! Ever!). It's also useful for callers to know something won't be changed. It is best to think about it in this way: if you omit const, you are saying the object will be modified.
Temporary objects: As another answer mentioned, C++ is much more about value-semantics. Temporary objects can be created and destroyed in expressions, for example:
std::string str = std::string("hello") + " world" + "!";
Here, the first + creates a temporary string with "hello world". The second + combines the temporary with "!", giving a temporary containing "hello world!", which is then copied to str. After the statement is complete, the temporaries are immediately destroyed. To further complicate things, C++0x adds rvalue references to solve this, but that's way out of the scope of this answer!
You can also bind temporary objects to const references (another useful part of const). Consider the previous function again:
void func(const MyClass& x)
This can be called explicitly with a temporary MyClass:
func(MyClass()); // create temporary MyClass - NOT the same as 'new MyClass()'!
A MyClass instance is created, on the stack, func2 accesses it, and then the temporary MyClass is destroyed automatically after func returns. This is convenient and also usually very fast, since the heap is not involved. Note 'new' returns a pointer - not a reference - and requires a corresponding 'delete'. You can also directly assign temporaries to const references:
const int& blah = 5; // 5 is a temporary
const MyClass& myClass = MyClass(); // creating temporary MyClass instance
// The temporary MyClass is destroyed when the const reference goes out of scope
Const references and temporaries are frequent in good C++ style, and the way these work is very different to C#.
RAII, exception safety, and deterministic destructors. This is actually a useful feature of C++, possibly even an advantage over C#, and it's worth reading up on since it's also good C++ style. I won't cover it here.
Finally, I'll just throw in this is a pointer, not a reference :)
The traditional stumbling blocks for people coming to C++ from C# or Java are memory management and polymorphic behavior:
While objects always live on the heap and are garbage collected in C#/Java, you can have objects in static storage, stack or the heap ('free store' in standard speak) in C++. You have to cleanup the stuff you allocate from the heap (new/delete). An invaluable technique for dealing with that is RAII.
Inheritance/polymorphism work only through pointer or reference in C++.
There are many others, but these will probably get you first.
Virtual destructors.
Header files! You'll find yourself asking, "so why do I need to write method declarations twice every time?"
Pointers and Memory Allocation
...I'm a C# guy too and I'm still trying to wrap my head around proper memory practices in C/C++.
Here is a brief overview of Managed C++ here. An article about writing an Unmanaged wrapper using the Managed C++ here. There is another article here about mixing Unmanaged with Managed C++ code here.
Using Managed C++ would IMHO make it easier to use as a bridge to the C# world and vice versa.
Hope this helps,
Best regards,
Tom.
The biggest difference is C#'s reference semantics (for most types) vs. C++'s value semantics. This means that objects are copied far more often than they are in C#, so it's important to ensure that objects are copied correctly. This means implementing a copy constructor and operator= for any class that has a destructor.
Raw memory twiddling. Unions, memsets, and other direct memory writes. Anytime someone writes to memory as a sequence of bytes (as opposed to as objects), you lose much of the ability to reason about the code.
Linking
Linking with external libraries is not as forgiving as it is in .Net, $DEITY help you if you mix something compiled with different flavors of the same msvcrt (debug, multithread, unicode...)
Strings
And you'll have to deal with Unicode vs Ansi strings, these are not exactly the same.
Have fun :)
The following isn't meant to dissuade in any way :D
C++ is a minefield of Gotcha's, it's relatively tame if you don't use templates and the STL -- and just use object orientation, but even then is a monster. In that case object based programming (rather than object-oriented programming) makes it even tamer -- often this form of C++ is enforced in certain projects (i.e., don't use any features that have even a chance of being naively used).
However you should learn all those things, as its a very powerful language if you do manage to traverse the minefield.If you want to learn about gotcha's you better get the books from Herb Sutter, Scott Myers, and Bjarne Stroustrup. Also Systematically going over the C++ FAQ Lite will help you to realize that it indeed does require 10 or so books to turn into a good C++ programmer.

Categories