DonLackomage Teach You Stupid Boy, Stupid Small Shit, To Understand And Learn .NET
It's a real talk man..:)
DonLackomage Teach You Stupid Boy, Stupid Small Shit, To Understand And Learn .NET
It's a real talk man..:)
1. Prologue
What is .NET
The .NET Framework is about:
٭ Microsoft .NET (pronounced “dot net”) is a software component that runs on the Windows operating system.
٭ .NET provides tools and libraries that enable developers to create Windows software much faster and easier.
٭ The .NET Framework must be installed on a user’s PC to run .NET applications.
.Net is the name which refers to a technology created by Microsoft as an attempt (or a step forward) to improve the old COM technology.
Finally .NET includes both the CLR and the .NET Framework, that is, a couple of additional libraries (a framework as one of the goals of .NET was to compete with the J2EE) which provides with a great deal of additional functionallity.
About COM objects:
COM (Common Object Model) technology, for those of you who haven't heart about it, is a technology which intents to be (and to a certain extent is) a communication protocol between application (local or remote) independent of the programming language used to write those applications. COM inserted new concepts like the separation between communication interfaces and actual implementation as well as the definition of contracts between the way communication was done. Nevertheless, COM brought with it a couple of problems in both its definition as well as it use.
In order to overcome the raising problems of COM (see the Don Box book) Microsoft started to work on a COM extension which finally ended becoming the CLR (Common Language Runtime) which is the core of the .NET languages and framework.
.NET, CLR, CLI, CTS or CIL
There's a couple of acronyms that come along frecuently when you're reading .NET documentation, CLR (common language runtime), CLI (common language infrastructure), CTS (common type system), CIL (common intermediate language).
· The "CLI" is the main specification of .NET, that is, the workings and system architecture. During the development of the CLR Microsoft has sent the specification of the CLR to several standards organizations, among them especially the ECMA. That way the CLI constitutes an specification of a system which provides all the characteristics .NET offers (type safety, managed code, intermediate language...)
- The CLI defines the specificaton of the "CTS", that is, the common type system which defines a type system and the inheritance which gives birth (in the .NET implementation) to the object hierarchy.
- The CLI defines too the specification of the "CIL" which constitutes the intermediate language, that is, that every implementation of the CLI must generate assemblies (we'll cover this later) using an intermediate language which later on will be compiled depending on the actual machine the code is running.
· The "CLR" (which paradoxically have to be explained the last) constitutes an implementation (in fact the only existing implementation) of the CLI.
Managed code
In .NET the code is said to be managed. As what is really executed is intermediate code, that execution is said to be "watched" so that no "inappropriate" actions can take place.
Garbage collector
.NET includes a garbage collector. That means that we don't need to worry about manually freeing the memory we are no longer using because the garbage collector (also know as just GC) will monitor the entire used memory, decide what "portions" of that memory can be accessed and, in case they can't, and set it out as it fits better.
Code Access Security (CAS)
.NET includes a system called CAS (Code Access Security) which allows to restrict the execution permissions for a given section of code in a detailed way. That means that we'll be able to define that a given code segment (associated to a given role) will have only read access to three files.
On the same way we will be able to configure our library, which provides with a couple of services, to provide different functionalities depending on the access level of the calling program (for example. we could prevent an application to create new documents based on its access level, or that it can only read certain kind of documents).
But I'm anti M$
If you have some basic believe against Microsoft that shouldn't be a barrier. There are several free developments which implement (or are in the process of implementing) the CIL specification as well as other parts of the ECMA specification so that they can execute intermediate code and thus assemblies (and executables) generated in that intermediate language. As far as I know there are to main implementation neither of which is complete (specially the latest functionality in the .NET 2.0).
· Plugin <em></em> Not Found The Mono Project is the name of a project started by Plugin <em></em> Not Found acquired later by Plugin <em></em> Not Found whose purpose was to create a series of tools compatible with .NET which followed the ECMA specification.
· Plugin <em></em> Not Found The Portable .NET project is the equivalent to the Mono Project but being developed by the Plugin <em></em> Not Found (Free Software Foundation).
Those two projects allow to executed .NET projects in Windows as well as in Linux (and I think other operating systems as well like FreeBSD, MacOsX, etc)
CIL, Assemblies and JIT (Just In Time) Compilation
Intermediate code, the PE Header and Mono
When we generate an executable or a dll in .NET, what's really being generated is not assembly code (object code being precise) the way that would happen if you were compiling with Visual Studio 6 or if you compile with Delphi, instead an special structure called assembly is created which contains the "translation" of the source code to the intermediate language code which is the core of .NET.
The PE header (PE comes from portable executable) is the structure of the Windows executables (both .exe and .dll) We could say that .NET extends or modify that header in a way that allows the .NET executables to be run transparently.
Into every executable there are several sections (logically divided into segments), code, data and stack. A traditional executable contains the PE header followed by the code section and then the rest of them if they are needed. In the case of a .NET executable the PE header is kept but after it there's a bootstrapper which is in charge of loading the CLR, the CLR "loader" to be precise which in turn access the text section which holds the intermediate code (the binary version of the intermediate code to be precise) of the application. That way, when windows runs the file, the CLR is automatically invoked and henceforth it takes over the execution of the intermediate code with out the user noticing anything.
Mono provides a similar functionality but, since the PE header is windows centric and Mono is not the execution of mono is something like "mono.exe exe_name" and therefore the part corresponding to the bootstraper and the call to the CLR is skipped and Mono just access the text section and runs it (that means that an executable generated by the mono compiler must be executed by mono as it lacks the bootstraper, at least I think so, I haven't test this so I'm not completely sure).
Assemblies
An assembly is the basic complete logical unit in .NET which encapsulates one or more code modules. I say complete because in reality you can generate a structure associated to a code module (which has the same name) that won't be able to be executed or used in any way but to be compiled into an assembly.
Each assembly contains a series of metadata whicg define the information contained in it. That metadata includes information like the external assemblies it is using, the classes, structs and methods which are defined in the assembly, etc. An assembly might include several code modules including functionality which, for semantic reasons, we may want to hold on a single executable file (assembly).
The only difference (in Windows) between a .exe and a .dll (in .NET) is the fact that the former has an "entry point" which must be unique and which defines the place where execution will begin, as well as a bootstrapper which will be in charge of loading the CLR.
Referenes (Static load of assemblies)
When we're programming in .NET, sometimes we need to use classes and functionality located in some external assembly (in fact we always need at least the mscorlib assembly which contains the System.Object class as well as a great part of the basic libraries of .NET). A reference is just a way to indicate that use and in fact they are translated into the CIL as an entry ".assembly extern mscorlib" and we will be able to see instructions like "isinst [mscorlib]System.Object"
Win Compilation
As I've already mentioned the code that .NET generates (with some minor exceptions) is intermediate code. This intermediate code is not interpreted during execution but compiled when it's needed. That compilation occurs somewhat in a lazy way (lazy compilation), which means it's only performed when (and only if) the code is going to be used.
The mechanism, in general terms, relays in the fact that, during the first execution, the method table of a class hold references to small pieces of JIT code. When the first call to a class method is issued the call direction obtained is not the real direction, instead the JIT one is obtained which in that moment compiles the intermediate code. Once the code has been compiled the JIT modifies the direction in the method table so all calls following after that first one hit the already compiled code.
System.Reflection
The same way that static assembly load exists we have the option to load assemblies dynamically by means of a library called System.Reflection.
Which traditional dlls the only thing we had was a table of addresses which contained the offset of the functions the dll exported... and that was about everything, we couldn't know what parameters the function expected, which, among other things, meant the parameters we handled were encoded as simple stack addresses which, possibly, could be executed by the dll or get corrupted or whatever hundred things may go wrong. In addition, since there wasn't a proper versioning system for dlls you could be calling a later or previous version whose specification doesn't fit nearly what you was expecting. All this ended up being known as "the dll hell" due to all the related problems it produced.
First of all one must understand that, due to the structure of an assembly which contains all the metainformation about what's inside itself, not only do we have the possibility to invoke certain functions (as was the case with old dlls) but also to get a much wider functionality.
Since we have all that information, the CLR can manage all calls to the code inside the assembly so we don't make "weird things".
In the other hand we can also examine the assembly in order to discover and analyze the functionality provided by it, searching, for example, for classes which implement a given interface, creating instance of that classes and treating them as if they were part of our own assembly.
Assembly.Load(ing)
The System.Reflection library provides several static method inside the Assembly class which allow us to open an assembly.
System.Reflection.Emit and System.CodeDom
Another interesting functionality provided by .NET is code generation in runtime, that is, emitting lines of intermediate code which will be compiled by the JIT in runtime and will result on assembler code which will execute as if it was code compiled with the VS.
In order to emit source code the .NET framework provides us with several libraries (at several levels). That libraries are mainly the System.Reflection.Emit and the System.CodeDom. With the System.Reflection.Emit we can, for example, create a new assembly, assign it a name, define module and classes, assign fields to the classes, define the constructor, define methods, etc.
P/Invoke (Platform Invoke)
Although the .NET framework is pretty wide and complex, there is still some functionality from the windows API which is not covered. In the same way, sometimes we need to access old functionality residing in old dlls (that is, not .NET) that we can't (or we do not want) to substitute with framework classes.
P/Invoke defines a service to invoke platform functions, that is, functionality from pre-CLR libraries.
P / Invoke defines the service invocation functions provided by the platform, ie, pre-CLR functionality libraries.
The DllImport attribute
The DllImport attribute, located in the System.Runtime.InteropServices, allows us to perform the aforementioned invocations, for example:
[DllImport("user32.dll")]
static extern bool CloseWindow(IntPtr hWnd);
static extern bool CloseWindow(IntPtr hWnd);
The declaration of the method is done by the reserved word "extern" which implies that that method isn't located in this assembly. As a parameter we supply the name of the library which contains the method we wish to use.
DllImport accepts several parameters:
· Value: The name of the library, this parameter is mandatory
· EntryPoint: This parameter is optional and allows us to define a different method in our assembly than the one located in the library.
[DllImport("user32.dll" EntryPoint = "CloseWindow")]
static extern bool MyOwnCloseWindow(IntPtr hWnd);
static extern bool MyOwnCloseWindow(IntPtr hWnd);
· SetLastError: A lot of windows libraries use the windows function "SetLastError", in order to guarantee that the error we recover (in case there's one) is correct, this parameter must be true.
"The Windows way"
On Windows the load of libraries through P/Invoke is a standard simple process, whenever a [DllImport] is found the compiler automatically generates the code corresponding to a LoadLibrary and a GetProcAddess.
"The Mono way"
With Mono things are a little more complicated. As Mono is multiplatform, several libraries can have different names between an instalation in Windows, Linux or MacOSX, and the same goes for its extensions (for example mlib.so.1.2 vs mlib.dll). I can't and its not an objective of this article to cover how does Mono manage to perform that operation transparently (for more information refer to this excellent [from Jonathan Pryor about P/Invoke]) but let's just say that it makes it so that the same [DllImport] directives that work with Windows will also work with Linux (even with calls to system libraries as Mono takes care to map that call to another library function which performs the same function as the one in Windows).
Abstract methods and interfaces
Abstract classes and methods
Generally we understand a pure abstract class as any class having only abstract methods.
Method abstraction is a very useful technique to define behavior patterns over the classes that are going to inherit from a given class we are defining.
An abstract method is a class method which won't be implemented but is expected to be implemented by the descendants of the class. In delphi, if you try to call that method you'll get a runtime exception as there isn't really any code there that can be called. A basic example of an abstract method and its used could be:
Interfaces
An interface is a way of defining a contract. When we talk about abstract classes we are defining characteristics of an object type, specifying what an object is but in the case of an interface we define a capability and we bond to provide that capability, we are talking about establishing a contract about what the object can do.
Interfaces express, as I've already mentioned, a capability. They do not express something like "a Doberman is a type of dog and every dog can walk" but more like "this thing can walk"
Or said in another way, the interface defines a contract so that if a class implements an interface then it guarantees it will fulfill that contract.
Contrary to what happens with inheritance, a class can implement as many interfaces as it wants, after all is just accepting a contract, so, in that way, if an object is renderable and can be affected by physics then it must implement both interfaces.
That way our two interfaces specify that, if we want to be able to be renderized we must implement a Render method, accepting the specified parameters. That way if my rendering process can get the list of objects that compose the scene, for each of those object, it could verify if the object is renderable and, if it is, render it without having to worry about specific class details.
When to use abstract classes and when to use interfaces
Decission about when to use what is being arround for long and is one of those discussions with a lot of people having its opinion or backing up this or that idea. I think there's a basic rule that works almost everytime: Use abstract lessons and inheritance if you can make the statement "A is a B".
Use interfaces if you can make the statement "A is capable of [doing] as", or also, abstract for what a class is, interface for what a class can do.
By example, we can say a triangle is a polygon but it makes no sense to say a triangle is capable of being a polygon.
Anyway, as ever, the rule of thumb for this is: use your common sense. Sometimes an interface just fit much better, even if the above rule tells you the contrary, if that's it just use the interface (after considering consequences of course).
Interview Samples
I. Given an array of ints, write a C# method to total all the values that are even numbers.
static long SumEvenNumbers(int[] arrayOfInt)
{
return arrayOfInt.Where(i => i%2 == 0).Sum(i=> (long) i);
}
II. What is the output of the short program below? Explain your answer.
class Program {
static String location;
static DateTime time;
static void Main() {
Console.WriteLine(location == null ? "location is null" : location);
Console.WriteLine(time == null ? "time is null" : time.ToString());
}
}
Output:
location is null
1/1/0001
String is reference type, but DateTime is value type so it can't be null.
III. Given an instance
circle of the following class:public sealed class Circle {
private double radius;
public double Calculate(Func<double, double> op) {
return op(radius);
}
}
write code to calculate the circumference of the circle, without modifying the
Circleclass itself.
The preferred answer would be of the form:
circle.Calculate(r => 2 * Math.PI * r);
Since we don’t have access to the private
radius field of the object, we tell the object itself to calculate the circumference, by passing it the calculation function inline.
A lot of C# programmers shy away from (or don’t understand) function-valued parameters. While in this case the example is a little contrived, the purpose is to see if the applicant understands how to formulate a call to
Calculate which matches the method’s definition.
Alternatively, a valid (though less elegant) solution would be to retrieve the radius value itself from the object and then perform the calculation with the result:
var radius = circle.Calculate(r => r);
var circumference = 2 * Math.PI * radius;
IV. What is the output of the program below? Explain your answer.
class Program {
private static string result;
static void Main() {
SaySomething();
Console.WriteLine(result);
}
static async Task<string> SaySomething() {
await Task.Delay(5);
result = "Hello world!";
return “Something”;
}
}
Also, would the answer change if we were to replace
await Task.Delay(5); with Thread.Sleep(5)? Why or why not?
The answer to the first part of the question (i.e., the version of the code with
await Task.Delay(5);) is that the program will just output a blank line (not “Hello world!”). This is because result will still be uninitialized when Console.WriteLine is called.
Most procedural and object-oriented programmers expect a function to execute from beginning to end, or to a
return statement, before returning to the calling function. This is not the case with C# async functions. They only execute up until the first awaitstatement, then return to the caller. The function called by await (in this case Task.Delay) is executed asynchronously, and the line after the await statement isn’t signaled to execute until Task.Delay completes (in 5 milliseconds). However, within that time, control has already returned to the caller, which executes the Console.WriteLine statement on a string that hasn’t yet been initialized.
Calling
await Task.Delay(5) lets the current thread continue what it is doing, and if it’s done (pending any awaits), returns it to the thread pool. This is the primary benefit of the async/await mechanism. It allows the CLR to service more requests with less threads in the thread pool.
Asynchronous programming has become a lot more common, with the prevalence of devices which perform over-the-network service requests or database requests for many activities. C# has some excellent programming constructs which greatly ease the task of programming asynchronous methods, and a programmer who is aware of them will produce better programs.
With regard to the second part of the question, if
await Task.Delay(5); was replaced with Thread.Sleep(5), the program would output Hello world!. An async method without at least one await statement in it operates just like a synchronous method; that is, it will execute from beginning to end, or until it encounters a return statement. Calling Thread.Sleep() simply blocks the currently running thread, so the Thread.Sleep(5) call just adds 5 milliseconds to the execution time of the SaySomething() method.
V. What is the output of the program below? Explain your answer.
delegate void Printer();
static void Main()
{
List<Printer> printers = new List<Printer>();
for (int i = 0; i < 10; i++)
{
printers.Add(delegate { Console.WriteLine(i); });
}
foreach (var printer in printers)
{
printer();
}
}
This program will output the number 10 ten times.
Here’s why: The delegate is added in the for loop and “reference” (or perhaps “pointer” would be a better choice of words) to i is stored, rather than the value itself. Therefore, after we exit the loop, the variable i has been set to 10, so by the time each delegate is invoked, the value passed to all of them is 10.
VI.
No comments:
Post a Comment