Microsoft .NET Framework
Arash Ebrahimpour
Email: Arash.Ebrahimpour@abo.fi
Department of Computer Science
Åbo Akademi University, FIN-20520 Turku, Finland
1 Introduction
The aim of this article is to provide a general introduction to the .NET platform. We will also introduce C# the new programming language from Microsoft that targets the .NET platform. We will cover the features of C#, and will try to compare it with other programming languages like C++, Java and Visual Basic.
The .NET Framework is a new computing platform that simplifies application development in the highly distributed environment of the Internet.
This is an important strategy for Microsoft and in their own words they are betting the company on this strategy.
The .NET Framework is a component oriented platform and standards based.
The .NET platform provides an infrastructure for object-oriented programming. It is built from the ground up to include garbage collection, exception handling and type safety.
At the core of the .NET Framework is the Common Language Runtime (CLR). The other important parts of the .NET Framework are the .NET Framework class library and a set of programming languages that target the Common Language Runtime.
-
Managed Applications
(Applications that target the .NET platform)
|
|
.NET Framework class library
|
The CLR
|
Operating system and hardware
|
Figure 1.1 - The relationship of the operating system, the Common Language Runtime, .NET Framework class library and your application
1.1 The Common Language Runtime
The Common Language Runtime is Microsoft's development platform of the future. In Microsoft's vision, most future software will be written to make use of the CLR features.
One can compare the CLR with Java Virtual Machine. The CLR manages code at execution time, providing core services such as code safety verification, compilation, code execution, memory management, thread management, remoting and other system services.
When developing applications for the .NET Framework, source code (in C# and other programming languages that target the .NET Framework) is compiled into metadata and Intermediate Language (IL), which is a CPU-independent set of instructions that can be efficiently converted into native code. IL is compiled to native code at run time by the CLR (A process called Just In Time compilation or JITing for short) and then this native code is executed. This means that code can be compiled to IL once and be run on different platforms. Also the JIT compiler can optimize the code for the specific CPU that the code is running on.
Code that targets the CLR is called managed code, because the CLR is taking care of it, providing the services that it needs and ensuring that it does not do anything that it is not supposed to do.
1.2 .NET Framework Class Library
The .NET Framework class library is a collection of object oriented reusable types that tightly integrate with the common language runtime. These types enable you to accomplish a range of common programming tasks, including tasks such as file access, string management, data collection and database connectivity. In addition to these common tasks, the class library includes types that support a variety of specialized development scenarios, e.g. there are classes for developing Windows GUI applications (Windows Forms), ASP.NET applications, Web Services, etc.
1.3 .NET Framework Languages
Microsoft ships five languages for .NET Framework developers: C#, Visual Basic.NET, IL (Intermediate Language), C++, and JScript.NET. All of these languages are interoperable. Language interoperability is the ability of code to interact with code that is written using a different programming language. It means that types can inherit implementation from other types, pass objects to another type's methods, and call methods defined on other types, regardless of the language the types are implemented in. For example in your C# code you can use a class that is implemented in Visual Basic.NET.
2 Introduction to C#
C# is a new programming language in the C/C++ family from Microsoft. It borrows a lot of features from C++ but is generally simpler and there are some other big differences.
2.1 Component Software
The CLR is a component-based environment, and C# that targets the CLR is designed to make component creation easier. C# is a component-centric language, in that all classes are written as components.
Software engineering is less and less about building monolithic applications and more and more about building components that slot into various execution environments; for example, a control in a browser or a business object that executes in ASP.NET. Key to such components is that they have methods, properties and events and that they have attributes that provide declarative information about the component that will be used by the execution environment or other code. All of these concepts are first class citizens in C# and the underlying runtime environment. Declarative information (known as attributes) can be applied to components to convey design-time and runtime information about the component. All these features make C# a very natural language to construct and use components. C# classes don’t require header files, IDL files, or type libraries. Components created by C# are self-describing and can be used without a registration process.
2.2 Robust and Durable Software for the Real-World
Software must have good performance, build on existing code, and be practical to write in terms of time and budget. A well designed environment is of little use if it does not provide enough power for real-world use.
C# provides the benefits of an elegant and unified environment, while still providing access to lower level features (such as pointers) when those features are needed to get the job done.
C# makes it easy to use the existing code. Existing COM objects can be used as if they were .NET objects and the CLR will make objects in the runtime appear to be COM objects to existing COM-based code. Native C code in DLL files can be called from C# code.
C# is close to C++ and C++ programmers will find it easy to learn C#. C# is a powerful object oriented programming language. Through use of concepts like boxing and unboxing, C# bridges the gap between primitive types and classes, allowing any piece of data to be treated as an object. Furthermore, C# introduces the concept of value types, which allows users to implement lightweight objects that do not require heap allocation.
C# components run in the CLR environment. C# is built from the ground up to include garbage collection, structured exception handling and type safety. Garbage collection takes the burden of memory management away from the programmer. Numerical operations can be checked to ensure that they don’t overflow, and arrays support bounds checking. The language is type safe and it protects against the use of variables that have not been initialized, unsafe casts, and other common programming errors.
2.3 C# Features
We will briefly cover some important and new features of C# and will provide some examples, so that we can better compare C# with other programming languages and technologies.
2.3.1 Object-Orientation
In the .NET CLR, all objects are derived from the ultimate base class named object, and only single inheritance is provided (i.e. an object can only be derived from one base class). This does prevent us from using multiple-inheritance that is available in other programming languages like C++, but it also eliminates many abuses of multiple-inheritance and makes things simpler. It is of course a tradeoff, and designers of the language believe that it a good tradeoff. Multiple-inheritance in the form of Interfaces is possible, but interfaces cannot contain implementation.
2.3.2 Garbage Collection
Heap allocation in .NET framework is very fast. All that the system has to do is make sure that there’s enough room in the managed heap for the requested object, return a pointer to that memory, and increment the pointer to the end of the object.
But the cleanup process is more complex. The .NET garbage collector uses a “Mark and Compact” algorithm. At collection time the garbage collector starts at root objects (static variables, local variables, etc) and finds all the objects that are referenced from those root objects. This way garbage collector knows which objects are in use and which ones are not. Then all the referenced objects are compacted in the managed heap and the pointers to these objects are fixed. Then the pointer to the next available memory area is moved to the end of used objects that are compacted. Since the garbage collector is moving objects and updating object references, all useful work must be stopped while the collection takes place.
Note that in C# and the .NET Framework unlike technologies like COM you do not have to think about reference counting and circular references and those kinds of bugs are completely eliminated.
2.3.3 Exception Handling, Efficiency and Overhead
In languages without garbage collection, adding exception handling is very expensive, since all objects within a function must be tracked to make sure that they are properly destroyed at any time that an exception could be thrown. The required tracking code both adds execution time and code size to a function.
In C# objects are tracked by the garbage collector rather than the compiler, so exception handling is very inexpensive to implement and imposes little runtime overhead when the exceptional case does not occur.
2.3.4 Polymorphism, Virtual Functions and Versioning
The C# language is designed such that versioning between base and derived classes in different libraries can evolve and maintain backwards compatibility. This means, for example, that the introduction of a new member in a base class with the same name as a member in a derived class is not an error. It also means that a class must explicitly state whether a method is intended to override an inherited method, or whether a method is a new method that simply hides a similarly named inherited method.
In C#, methods are by default, not virtual. To make a method virtual, the virtual modifier has to be used in the method declaration of the base class. The derived class can then override the base virtual method by using the override keyword or hide the virtual method in the base class by using the new keyword. If neither the override keyword nor the new keyword is specified, the compiler will issue a warning and the method in the derived class will hide the method in the base class.
2.3.5 Heap or Stack? Classes vs. Structs
In the CLR data types are separated into “value types” and “reference types”. Value types are either stack-allocated or allocated inline in a structure. Reference types are heap-allocated. In C# classes are reference type and heap allocated but structs are value types and stack allocated.
Both reference types and value types are derived from the ultimate base class object. In cases where a value type needs to act like an object, a wrapper that makes the value type look like an object is allocated on the heap and the value type is copied into it. This process is known as boxing, and the reverse process is known as unboxing. This concept of boxing and unboxing lets you treat any type as an object.
2.3.6 Statements
The statements in C# are close to C++, with a few modifications. The foreach statement is used to iterate over members of an array or a collection. The lock statement is used for mutual exclusion in threading scenarios. The checked and unchecked statements are used to control overflow checking in arithmetic operations and conversions.
In C# it is possible to pass arguments to a function by reference and this feature is sometimes very convenient. For example in C# you can implement a Swap function or pass an int by reference to a function and the function can change the variable, etc.
2.3.7 Delegates and Events
Delegates are a type-safe, object oriented implementation of function pointers and are used in many situations where a component needs to call back to the component that is using it. They are used as the basis for events.
Using a delegate allows the programmer to encapsulate a reference to a method inside a delegate object. The delegate object can then be passed to code which can call the referenced method, without having to know at compile time which method will be invoked.
A delegate declaration defines a type that encapsulates a method with a particular set of arguments and return type. For static methods, a delegate object encapsulates the method to be called. For instance methods, a delegate object encapsulates both an instance and a method on the instance. If you have a delegate object and an appropriate set of arguments, you can invoke the delegate with the arguments.
An interesting and useful property of a delegate is that it does not know or care about the class of the object that it references. Any object will do; all that matters is that the method's argument types and return type match the delegate's. This makes delegates perfectly suited for anonymous invocation.
This example shows a simple use of delegates:
public class Book
{
private string title;
private string author;
public Book(string title, string author)
{
this.title = title;
this.author = author;
}
public override string ToString()
{
return this.title + "\t" + this.author;
}
}// class Book
public delegate void ProcessBookCallback(Book book);
public class BookDb
{
private ArrayList books = new ArrayList();
public void Add(Book book)
{
books.Add(book);
}
public void ProcessBooks(ProcessBookCallback processBook)
{
foreach(Book book in books)
{
processBook(book);
}
}
}// class BookDb
class Test
{
public static void Main()
{
BookDb bookDb = new BookDb();
bookDb.Add(new Book("title1", "author1"));
// add more books
bookDb.ProcessBooks(new ProcessBookCallback(PrintBook));
}
private static void PrintBook(Book book)
{
Console.WriteLine(book);
}
}// class Test
2.3.7.1 Delegates vs. Interfaces
Delegates and interfaces are similar in that they enable the separation of specification and implementation. Multiple independent authors can produce implementations that are compatible with an interface specification. Similarly, a delegate specifies the signature of a method, and authors can write methods that are compatible with the delegate specification. When should you use interfaces, and when should you use delegates?
Delegates are useful when:
-
A single method is being called.
-
A class may want to have multiple implementations of the method specification.
-
It is desirable to allow using a static method to implement the specification.
-
An event-like design pattern is desired.
-
The caller has no need to know or obtain the object that the method is defined on.
Interfaces are useful when:
-
The specification defines a set of related methods that will be called.
-
A class typically implements the specification only once.
-
The caller of the interface wants to cast to or from the interface type to obtain other interfaces or classes.
2.3.7.2 Events
Delegates are ideally suited for use as events (notifications from one component to "listeners" about changes in that component). Events in the .NET Framework are based on the delegate model and are first class citizens. Here is a simple example:
class Test
{
static void Main()
{
Button button = new Button();
ClickListener listener = new ClickListener();
// subscribe for the Click event
button.Click += new ClickHandler(listener.ButtonClicked);
button.SimulateClick();
}
}
delegate void ClickHandler(object sender, EventArgs args);
class Button
{
public event ClickHandler Click;
public void SimulateClick()
{
if(Click != null)
Click(this, EventArgs.Empty);
}
}
class ClickListener
{
public void ButtonClicked(object sender, EventArgs args)
{
Console.WriteLine("Event was fired");
}
}
Output:
Event was fired
2.3.8 Attributes
Attributes are used in C# and .NET Framework to communicate declarative information from the writer of the code to other code that is interested in the information. This could be used to specify which fields of an object should be serialized, which transaction context to use when executing a method, how to display a class in a class browser or declaring design time information for a control.
A very simple attribute usage might look like this:
public class Employee
{
[XmlAttribute]
public string id;
public string name;
}
Here XmlAttribute is applied to member variable id. The process of XML Serialization will use this attribute at runtime. Without applying this attribute the result of XML serialization of an Employee object will be something like this:
1234
John Smith
But after applying the attribute the result of XML Serialization will be like this:
John Smith
Attribute information is retrieved at runtime through reflection. New attributes can be written and applied to elements of the code (such as classes, members, etc) and retrieved through reflection.
2.3.9 Reflection and Execution-Time Code Generation
If you are a C++ programmer, it is likely that you have a compile-time view of the world. Because a C++ compiler does all the code generation when the code is compiled, C++ programs are static systems that are fully known at compile time. In the .NET framework the compile-time world still exists, but it is also possible to build more dynamic systems where new code is loaded at runtime or even code is created on the fly, although runtime code generation is rarely used in most software projects.
For some algorithms, it is easy to write a general solution to a problem, but the overhead of the general solution may be undesirable. A custom solution to the problem may be possible but cannot be generated ahead of time because some details of the problem are not known until the runtime. For example, in the .NET Framework, runtime code generation is used for implementing regular expressions.
In the .NET framework, it is also possible to dynamically create an instance of a type, determine the members, properties, functions that are implemented by a type and call the functions, etc.
2.3.10 Security in the .NET Framework
Security is one of the most important issues to consider when moving from traditional program development, where administrators often install software to a fixed location on a local disk, to an environment that allows for dynamic downloads and execution and even remote execution. To support this model, the Microsoft .NET Framework provides a rich security system, capable of confining code to run in tightly constrained, administrator-defined security contexts.
Many security models attach security to users and their groups (or roles). This means that users, and all code run on behalf of these users, are either permitted or not permitted to perform operations on critical resources. This is how security is modeled in most operating systems. The .NET Framework provides a security model called role-based security that functions in a similar vein.
Additionally, the .NET Framework also provides security on code and this is referred to as code access security (also referred to as evidence-based security). Code access security allows the execution of code in semi-trusted security context, based on the identity of code. With code access security, a user may be trusted to access a resource but if the code the user executes is not trusted, then access to the resource will be denied. Security based on the identity of code, as opposed to specific users, is a fundamental facility to permit security to be expressed on mobile code.
2.3.11 Application Domains
Historically, process boundaries have been used to isolate applications running on the same computer. Each application is loaded into a separate process, which isolates the application from other applications running on the same computer.
The applications are isolated because memory addresses are process-relative; a memory pointer passed from one process to another cannot be used in any meaningful way in the target process. In addition, you cannot make direct calls between two processes. Instead, you must use proxies, which provide a level of indirection.
Managed code must be passed through a verification process before it can be run (unless the administrator has granted permission to skip the verification). The verification process determines whether the code can attempt to access invalid memory addresses or perform some other action that could cause the process in which it is running to fail to operate properly. Code that passes the verification test is said to be type-safe. The ability to verify code as type-safe enables the common language runtime to provide as great a level of isolation as the process boundary, at a much lower performance cost.
Application domains provide a secure and versatile unit of processing that the common language runtime can use to provide isolation between applications. You can run several application domains in a single process with the same level of isolation that would exist in separate processes, but without incurring the additional overhead of making cross-process calls or switching between processes. The ability to run multiple applications within a single process dramatically increases server scalability.
The isolation provided by application domains has the following benefits:
-
An application can be independently stopped.
-
An application cannot directly access code or resources in another application.
-
A fault in an application cannot affect other applications.
-
Configuration information is scoped by application. This means that an application controls the location from which code is loaded and the version of the code that is loaded.
3 Comparing C# to other technologies and programming languages
3.1 C# and C++
A lot of things in C# are similar to C++, but there are some big differences. C# borrows a lot of features from C++ but is generally simpler. This simplicity comes at a cost. You get a slight performance tradeoff for better productivity. If you do not have time and resource limitations you will generally do better with C++.
C# code runs in the .NET runtime environment. This means that there are many things that are not under programmer’s control.
Object deletion is done by the garbage collector sometime after the object is no longer used. Destructors (Finalizers) can be used for cleaning up unmanaged resources like database connections or operating system resources, but the semantics of C++ destructors is different.
Pointers are not used generally in C#, it is possible to use pointers in unsafe mode, but it is rarely used.
Source code is compiled to assemblies, which contain both the IL and metadata to describe the compiled code. All .NET languages query the metadata to determine the same information that is contained in C++ header files, therefore header files are not needed.
Calling native code requires a bit more work and there is an overhead also.
Exception handling is used instead of error returns.
In C# we have only single inheritance.
In C# objects are allocated on the heap, but note that heap allocation is very fast. Lightweight objects can be declared as structs and they are allocated on the stack instead of the heap.
All the statements that test a Boolean condition now require a variable of type bool. There is no automatic conversion from int to bool.
Arithmetic operations can be checked for overflow using checked and unchecked keywords.
Variables should be assigned a value before being used.
C# is generally more dynamic, a lot of metadata is associated with the code and it is possible to extend this metadata with custom attributes. It is possible to reflect into the code and gather information about types, load code at runtime and generate code on the fly.
C# has no header files, all code is written inline, and while there is preprocessor support for conditional compilation, there is no support for macros. These restrictions make it easier and faster for the compiler to parse code, and also make it easier for development environments to understand C# code.
There is no order dependency in C# code, and no forward declarations and the order of classes in source file is unimportant.
These C++ features are missing in C#:
-
const member functions or parameters
-
Global variables
-
Typedef
-
Conversion by construction
-
Default arguments on function parameters
3.2 C# and Java
There are a lot of similarities between C# and Java, however there are some differences between them. One of the differences between C# and Java is that design of C# is closer to C++.
C# has more primitive types than Java.
In Java, the primitive data types are in a separate world from the object-based types. For primitive types to be used in the object based world they must be put into an instance of a wrapper class. In C# primitive data types are stack-allocated as in Java, but they are also considered to be derived from the ultimate base class object. This means that primitive types can have member functions, e.g. you can write 5.ToString(). Whenever a primitive type is used in a situation where a parameter of type object is required, the compiler will automatically box the primitive type into a heap-allocated wrapper. Here is an example:
int i = 5;
object obj = i; // box i into obj
Console.WriteLine("i = {0}", obj);
int j = (int)obj; //unbox obj back to an int
In real code declaration of object variable is not needed, i will be passed directly.
In C#, it is possible to extend the type system by implementing custom value types using the struct keyword. These types are allocated on the stack, are boxed and unboxed as necessary, can have member functions and operators and explicit and implicit conversions defined on them. A struct is written using the same syntax as a class, except that a struct cannot have a base class (other than the implicit base class object), though it can implement interfaces.
C# and Java classes are quite similar, although there are some important differences and some minor syntactical differences.
In C#, all methods are non-virtual by default, and virtual must be specified explicitly to make a function virtual. Because of this there are no final methods in C#, though the equivalent of a final class can be achieved using sealed. C# provides better versioning support than Java.
C# allows programmers to overload most operators for both classes and structs so that objects can participate in arithmetic expressions.
In Java, parameters are always passed by value. C# allows parameters to be passed by reference by using the ref keyword. This allows a function to change the value of a parameter.
In C# we have enum types that are quite similar to C++ enum types.
Java interfaces can have constants, C# interfaces cannot. C# explicit interface implementation allows a class to implement two interfaces from two different sources that have the same member name.
In Java the property idiom is used by declaring get and set methods. In C# a property appears to the user of a class as a field, but has a get and set accessor to perform the read and/or write operations.
class Test
{
static void Main()
{
Employee employee = new Employee("John", "Address", 30);
Console.WriteLine("Name: {0}\tAddress: {1}\tAge: {2}",
employee.Name, employee.Address, employee.Age);
employee.Address = "New Address";
employee.Age += 1;
Console.WriteLine("Name: {0}\tAddress: {1}\tAge: {2}",
employee.Name, employee.Address, employee.Age);
}
}// class Test
public class Employee
{
private string name;
private string address;
private byte age;
public Employee(string name, string address, byte age)
{
this.name = name;
this.address = address;
this.age = age;
}
public string Name
{
get { return name; }
}
public string Address
{
get { return address; }
set { address = value; }
}
public byte Age
{
get { return age; }
set { age = value; }
}
}// class Employee
In Java when an object needs to receive a callback, an interface is used, the object implements that interface and a method of that interface is called for the callback. This approach can be used in C#. C# adds delegates which can be thought of as type safe function pointers. A class can create a delegate on a function in the class, and then the delegate can be passed to a function that accepts the delegate. That function can then call the delegate. Events are built upon delegates, which provide a publish-and-subscribe idiom. If a button implements a click event, any number of other classes can register a delegate to be called when that event is fired.
In C# we can add declarative information to the code that can be used at runtime by the runtime environment or other code through reflection.
Java does not detect overflow in conversions or mathematical expressions. In C# using checked and unchecked keywords the programmer can check for overflows. In a checked context overflows will throw an exception but the same operations in an unchecked context will not throw exceptions. The default context is controlled by a compiler flag.
Unsafe code in C# allows the use of pointers, when performance is extremely important or for using existing software, such as COM components or native C code in DLLs. Because unsafe code cannot be verified to be safe by the runtime, it can be executed if it is fully trusted by the runtime. This may make problems when the code should be downloaded from the Internet.
C# allows a variable number of parameters to be passed to a function using params keyword.
3.3 C# and Visual Basic 6
C# and Visual Basic 6 are very different programming languages. C# is a powerful object-oriented language while Visual Basic 6 has only limited object-oriented features.
In C# we have inheritance, overloading, constructors and destructors, interfaces, delegates, static members, attributes and multithreading support.
There are a lot of differences in the syntax of these two languages.
One important difference is that C# is stricter on variable declaration and usage. All variables must be declared with a specific type. In C# there is not a Variant data type, the object type can contain any type but it knows exactly what type it contains. There are some differences in primitive types also.
Conversion between types in C# is stricter than in Visual Basic. If detecting overflow during conversions is important, the checked statement can be used to turn on the detection of overflow.
In C# the class is the major organizational unit. Rather than having code or variables live in a global area, they are always associated with specific class. This results in a better organization of code, and makes the code more understandable.
There is no On Error statement in C#. Error conditions are communicated through exceptions.
3.4 Visual C++ .NET and Visual Basic .NET
Visual C++ and Visual Basic have been extended to work in the .NET framework.
Visual C++ .NET extends the standard C++ language to make it easy to add support for the .NET framework to new and existing applications. A set of “Managed Extensions” have been added to the language to allow programmers to produce and consume components that target the CLR. The visual C++ model allows programmer more control than the C# model, in that the user is allowed to write both managed and unmanaged code. It is not compulsory to use Managed Extensions but there are advantages to doing so. A program written using managed code using Managed Extensions for C++, for example, can operate with the CLR to provide services such as memory management, cross-language interoperation, code access security, and automatic lifetime control of objects.
A .NET component is created by using keywords to modify the meaning of existing C++ constructs. For example, when the __gc keyword is placed in front of a class definition, it enables the creation of a managed class and restricts the class from using constructs that are not allowed in the .NET world (such as multiple-inheritance).
Visual Basic has also seen considerable improvements. It now has object-oriented features such as inheritance, encapsulation, overloading and interfaces.
3.5 .NET vs. COM
3.5.1 Easier deployment and the end of DLL hell
The .NET Framework introduces several new features aimed at simplifying application deployment and solving DLL Hell.
Today installing an application involves copying a number of software components to the disk and making a series of registry entries that describe those components to the system. The separation between the entries in the registry that describe the component and the files on disk makes it difficult to install and uninstall components. Components are neither self-contained nor self-describing.
Another common problem in today's components-based systems is known as DLL Hell. DLL Hell refers to the set of problems caused when multiple applications attempt to share a common component like a dynamic-link library (DLL) or a Component Object Model (COM) class. In the most typical case, one application will install a new version of the shared component that is not backward compatible with the version already on the machine. Although the application that has just been installed works fine, existing applications that depended on a previous version of the shared component might no longer work.
The .NET framework addresses previous problems. In the .NET world “assemblies” are the self-describing, versionable deployment units of types and resources used to solve the previous versioning and deployment issues. In many ways an assembly equates to a DLL in today's world; in essence, assemblies are "logical DLLs”.
3.5.1.1 Application-Private Assemblies
A principle design guideline in .NET is that of isolated components (or assemblies). Isolating an assembly means that an assembly can only be accessed by one application (i.e. it is not shared by multiple applications). Isolation gives a developer absolute control over the code that is used by his application. Isolated, or application-private, assemblies are the default in .NET applications.
Application-private assemblies are deployed within the directory structure of the application in which they are used.
3.5.1.2 Shared Assemblies
However, there are cases where sharing an assembly between applications is necessary.
In .NET, sharing code between applications is an explicit decision. Assemblies that are shared have some additional requirements. In the .NET framework it is possible to install and run multiple versions of the same assembly on the same machine.
In addition, the .NET Framework allows applications and administrators to override the version of an assembly that is used by the application by specifying version policies.
The main features of the .NET Framework regarding deployment includes:
-
Application-Private components by default.
By default, components are deployed to the application directory and are visible only to the containing application.
-
Side-by-side versioning.
Multiple versions of a component or application can coexist, you can choose which versions to use, and the common language runtime enforces versioning policy.
-
XCOPY deployment and replication.
Self-described and self-contained components and applications can be deployed without registry entries or dependencies.
3.5.2 Other enhancements
While COM supports only limited object-oriented features, the .NET platform provides a powerful infrastructure for object-oriented programming. In C# we have inheritance, overloading, constructors and destructors, interfaces, delegates, static members, attributes and multithreading support.
COM developers are accustomed to implementing reference counting as a manual memory management technique. Each time an object is referenced, a counter is incremented. When a reference to an object goes out of scope, the counter is decremented. When an object's reference count reaches zero, the object is terminated and its memory is freed.
The reference counting scheme is the source of many bugs. If the reference counting rules are not followed precisely, objects might be freed prematurely or unreferenced objects might accumulate in memory. Circular references are also a common source of bugs. A circular reference occurs when a child object has a reference to a parent object, and the parent object has a reference to the child object. This scenario prevents either object from being released or destroyed. The only solution is for the parent and child objects to agree on a fixed pattern of usage and destruction.
When you develop applications in C# or other managed languages, the runtime's garbage collector eliminates the need for reference counting and, as a result, the bugs that can arise from this manual memory management scheme. Also you do not have to think about the circular references at all.
4 Classification
4.1 The ACM Special Interest Groups
Programming Languages (SIGPLAN)
Software Engineering (SIGSOFT)
4.2 The ACM Computing Classification System
D.3.2 Object-oriented languages
D.2.11 Languages
D.1.5 Object-oriented Programming
D.3.3 Language Constructs and Features (Classes and objects, Data types and structures, Inheritance, Modules, packages, Polymorphism)
D.2.7 Portability
D.2.13 Reuse models
D.2.7 Extensibility
5 References
Gunnerson, Eric - Programmer's introduction to C#
http://www.msdn.microsoft.com/
http://www.gotdotnet.com/
http://www.develop.com/
Share with your friends: |