|
Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts
Home » Posts filed under C#
Let us Learn Tuple-Part1
C# in Depth: C# and beforefielinit
It's worth noting that the v4 CLR behaves differently compared with the v1 and v2 CLRs here - all of them obey they specification, but the v4 CLR is genuinely lazy in many cases where earlier versions are eager. What should be done?I propose the following changes:
Further thoughts (after discussion on newsgroups)The first of the above proposals is definitely the most controversial. (The last isn't controversial at all, as far as I can see.) The reason is performance. Not many classes actually need the behaviour assumed by many C# programmers - most people need never know the difference, really. The JIT compiler, however, cares quite a lot: if a static member is used within a fairly tight loop, for instance, it makes a lot of sense to initialise the type before entering the loop, knowing thereafter that the type has already been initialised. When code is shared between app domains etc, I gather this becomes even more important.Making the performance of existing code decrease by recompilation with a new version of the framework would undoubtedly be unpopular. I'm therefore willing to concede as a less-than-ideal proposal - indeed I've only left it in this page for historical reasons (I dislike the idea of being a revisionist). The second proposal, however, is still important - both to allow classes which do have a static constructor to improve their performance with BeforeFieldInit semantics if appropriate, and to allow classes which currently only need a static constructor to get rid of BeforeFieldInit semantics to achieve this aim in a more self-documenting manner. (A junior developer is more likely to remove a static constructor which appears to be a no-op than to remove an attribute they don't fully understand.) View on the web | Inoreader is a light and fast RSS Reader. Follow us on Twitter and Facebook. | |
C# in Depth: Overloading
|
Strings in C# and .NET
|
Value vs Reference Types in C#
|
}
Assigning null to f has no effect because f is a copy of a reference, and we've only erased the copy.
We can change the way parameters are marshalled with the ref modifier. When passing by "reference", the method interacts directly with the caller's arguments. In the example below, you can think of the parameters p and f being replaced by myPoint and myForm:
Point myPoint = new Point (0, 0); // a new value-type variable Form myForm = new Form(); // a new reference-type variable
Test (ref myPoint, ref myForm); // pass myPoint and myForm by reference
void Test (ref Point p, ref Form f)
{
p.X = 100; // This will change myPoint's position
f.Text = "Hello, World!"; // This will change MyForm's caption
f = null; // This will nuke the myForm variable!
}
In this case, assigning null to f also makes myForm null, because this time we're dealing with the original reference variable and not a copy of it.Test (ref myPoint, ref myForm); // pass myPoint and myForm by reference
void Test (ref Point p, ref Form f)
{
p.X = 100; // This will change myPoint's position
f.Text = "Hello, World!"; // This will change MyForm's caption
f = null; // This will nuke the myForm variable!
}
Memory Allocation
The Common Language Runtime allocates memory for objects in two places: the stack and the heap. The stack is a simple first-in last-out memory structure, and is highly efficient. When a method is invoked, the CLR bookmarks the top of the stack. The method then pushes data onto the stack as it executes. When the method completes, the CLR just resets the stack to its previous bookmark—"popping" all the method's memory allocations is one simple operation!In contrast, the heap can be pictured as a random jumble of objects. Its advantage is that it allows objects to be allocated or deallocated in a random order. As we'll see later, the heap requires the overhead of a memory manager and garbage collector to keep things in order.
To illustrate how the stack and heap are used, consider the following method:
void CreateNewTextBox()
{
TextBox myTextBox = new TextBox(); // TextBox is a class
}
In this method, we create a local variable that references an object. The local variable is stored on the stack, while the object itself is stored on the heap:{
TextBox myTextBox = new TextBox(); // TextBox is a class
}

The stack is always used to store the following two things:
- The reference portion of reference-typed local variables and parameters (such as the myTextBox reference)
- Value-typed local variables and method parameters (structs, as well as integers, bools, chars, DateTimes, etc.)
- The content of reference-type objects.
- Anything structured inside a reference-type object.
Memory Disposal
Once CreateNewTextBox has finished running, its local stack-allocated variable, myTextBox, will disappear from scope and be "popped" off the stack. However, what will happen to the now-orphaned object on the heap to which it was pointing? The answer is that we can ignore it—the Common Language Runtime's garbage collector will catch up with it some time later and automatically deallocate it from the heap. The garbage collector will know to delete it, because the object has no valid referee (one whose chain of reference originates back to a stack-allocated object). C++ programmers may be a bit uncomfortable with this and may want to delete the object anyway (just to be sure!) but in fact there is no way to delete the obje ct explicitly. We have to rely on the CLR for memory disposal—and indeed, the whole .NET framework does just that!However there is a caveat on automatic destruction. Objects that have allocated resources other than memory (in particular "handles", such as Windows handles, file handles and SQL handles) need to be told explicitly to release those resources when the object is no longer required. This includes all Windows controls, since they all own Windows handles! You might ask, why not put the code to release those resources in the object's finalizer? (A finalizer is a method that the CLR runs just prior to an object's destruction). The main reason is that the garbage collector is concerned with memory issues and not resource issues. So on a PC with a few gigabytes of free memory, the garbage collector may wait an hour or two before even getting out of bed!
So how do we get our textbox to release that Windows handle and disappear off the screen when we're done with it? Well, first, our example was pretty artificial. In reality, we would have put the textbox control on a form in order to make it visible it in the first place. Assuming myForm was created earlier on, and is still in scope, this is what we'd typically do:
myForm.Controls.Add (myTextBox);
As well as making the control visible, this would also give it another referee (myForm.Controls). This means that when the local reference variable myTextBox drops out of scope, there's no danger of the textbox becoming eligible for garbage collection. The other effect of adding it to the Controls collection is that the .NET framework will deterministically call a method called Dispose on all of its members the instant they're no longer needed. And in this Dispose method, the control can release its Windows handle, as well as dropping the textbox off the screen.The same thing applies to classes such as FileStream—these need to be disposed too. Fortunately, C# provides a shortcut for calling Dispose on such objects, in a robust fashion: the using statement:
using (Stream s = File.Create ("myfile.txt"))
{
...
}
This translates to the following code:{
...
}
Stream s = File.Create ("myfile.txt");
try
{
...
}
finally
{
if (s != null) s.Dispose();
}
The finally block ensurse that Dispose still gets executed should an exception be thrown within the main code block.try
{
...
}
finally
{
if (s != null) s.Dispose();
}
A Windows Forms Example
Let's look a couple more types you'll come across often in Windows Forms applications. Size is a type used for representing a 2-dimensional extent and Font, as you would expect, encapsulates a font and its properties. You can find them in the .NET framework, in the System.Drawing namespace. The Size type is a struct—rather like Point, while the Font type is a class. We'll create an object of each type:
Size s = new Size (100, 100); // struct = value type Font f = new Font ("Arial",10); // class = reference type

and we'll also create a form. Form is a class in System.Windows.Forms namespace, and is hence a reference type:
Form myForm = new Form();
To set the form's size and font, we can assign the objects s and f to the form via its properties:
myForm.Size = s;
myForm.Font = f;
myForm.Font = f;
Here's what it now looks like in memory:

As you can see, with s, we've copied over its contents, while in the case of f, we've copied over its reference (resulting in two pointers in memory to the same Font object). This means that changes made via s will not affect the form, while changes made via f, will.
Fun with Structs
We've made a slightly simplifying assumption in the diagrams in that Size and Font are depicted as fields in the Form class. More accurately, they are properties, which are facades for internal representations we don't get to see. We can imagine their definitions look something like this:
class Form
{
// Private field members
Size size;
Font font;
// Public property definitions
public Size Size
{
get { return size; }
set { size = value; fire resizing events }
}
public Font Font
{
get { return font; }
set { font = value; }
}
}
By using properties, the class has an opportunity to fire events when the form's size or font changes. It provides further flexibility in that other size-related properties, such as ClientSize (the size of a control's internal area without title bar, borders, or scroll bars) can work in tandem with the same private fields.{
// Private field members
Size size;
Font font;
// Public property definitions
public Size Size
{
get { return size; }
set { size = value; fire resizing events }
}
public Font Font
{
get { return font; }
set { font = value; }
}
}
But there is a snag. Suppose we want to double the form's height, through one of its properties. It would seem reasonable to do this :
myForm.ClientSize.Height = myForm.ClientSize.Height * 2;
or more simply:
myForm.ClientSize.Height *= 2;
However, this generates a compiler error:Cannot modify the return value of 'System.Windows.Forms.Form.ClientSize' because it is not a variable
We get the same problem whether we use Size or ClientSize. Let's look at why.
Imagine ClientSize as a public field rather than a property. The expression myForm.ClientSize.Height would then simply reach through the membership hierarchy in a single step and access the Height member as expected. But since ClientSize is a property, myForm.ClientSize is first evaluated (using the property's get method), returning an object of type Size. And because Size is a struct (and hence a value-type) what we get back is a copy of the form's size. And it's this copy whose size we double! C# realizes our mistake, and generates an error rather than compiling something that it knows won't work. (Had Size been defined instead as a class, there would have been no problem, since ClientSize
's get accessor would have returned a reference, giving us access to the form's real Size object.)
So how then do we change the form's size? You have to assign it a whole new object:
myForm.ClientSize = new Size
(myForm.ClientSize.Width, myForm.ClientSize.Height * 2);
There's more good news in that with most controls we usually size them via their external measurements (Size rather than ClientSize) and for these we also have ordinary integer Width and Height properties that we can get and set!(myForm.ClientSize.Width, myForm.ClientSize.Height * 2);
View on the web
Inoreader is a light and fast RSS Reader. Follow us on Twitter and Facebook.
C# in Depth: Implementing the Singleton Pattern
|


