Documente Academic
Documente Profesional
Documente Cultură
This is where you can set the specific variables for the Application and Session
objects.
Can you explain what inheritance is and an example of when you might use
it?
When you want to inherit (use the functionality of) another class. Example: With a
base class named Employee, a Manager class could be derived from the Employee
base class.
Whats an assembly?
Assemblies are the building blocks of the .NET framework.
Describe the difference between inline and code behind.
Inline code written along side the html in a page. Code-behind is code written in a
separate file and referenced by the .aspx page.
What property must you set, and what method must you call in your code, in
order to bind the data from a data source to the Repeater control?
You must set the DataSource property and call the DataBind method.
Which property on a Combo Box do you set with a column name, prior to
setting the DataSource, to display data in the combo box?
DataTextField property.
Which control would you use if you needed to make sure the values in two
different controls matched?
CompareValidator control.
How many classes can a single .NET DLL contain?
It can contain many classes.
What is ViewState?
ViewState allows the state of objects (serializable) to be stored in a hidden field on
the page. ViewState is transported to the client and back to the server, and is not
stored on the server or any other external source. ViewState is used the retain the
state of server-side objects between postabacks.
What are the different types of Session state management options available
with ASP.NET?
ASP.NET provides In-Process and Out-of-Process state management. In-Process
stores the session in memory on the web server. This requires the a "sticky-server"
(or no load-balancing) so that the user is always reconnected to the same web
server. Out-of-Process Session state management stores data in an external data
source. The external data source may be either a SQL Server or a State Server
service. Out-of-Process state management requires that all objects stored in session
are serializable.
Can you explain what inheritance is and an example of when you might use
it?
When you want to inherit (use the functionality of) another class. Example: With a
base class named Employee, a Manager class could be derived from the Employee
base class.
Whats an assembly?
Assemblies are the building blocks of the .NET framework.
What property must you set, and what method must you call in your code, in
order to bind the data from a data source to the Repeater control?
You must set the DataSource property and call the DataBind method.
Which property on a Combo Box do you set with a column name, prior to
setting the DataSource, to display data in the combo box?
DataTextField property.
Which control would you use if you needed to make sure the values in two
different controls matched?
CompareValidator control.
What namespace does the Web page belong in the .NET Framework class
hierarchy?
System.Web.UI.Page
Can you explain the difference between an ADO.NET Dataset and an ADO
Recordset?
Valid answers are:
· A DataSet can represent an entire relational database in memory, complete with
tables, relations, and views.
· A DataSet is designed to work without any continuing connection to the original
data source.
· Data in a DataSet is bulk-loaded, rather than being loaded on demand.
· There's no concept of cursor types in a DataSet.
· DataSets have no current record baller You can use For Each loops to move through
the data.
· You can store many edits in a DataSet, and write them to the original data source
in a single operation.
· Though the DataSet is universal, other objects in ADO.NET come in different
versions for different data sources.
7. Can the validation be done in the server side? Or this can be done only in
the Client side?
Client side is done by default. Server side validation is also possible. We can switch
off the client side and server side can be done.
9. What is ADO .NET and what is difference between ADO and ADO.NET?
ADO.NET is stateless mechanism. I can treat the ADO.Net as a separate in-memory
database where in I can use relationships between the tables and select insert and
updates to the database. I can update the actual database as a batch.
The .NET Platform programming languages - including Visual Basic .NET, Visual C#,
and Visual C++ with managed extensions, and many other programming languages
from various vendors - use .NET Framework services and features through a
common set of unified classes. The .NET unified classes provide a consistent method
of accessing the platform's functionality. If you learn to use the class library, you will
find that all tasks follow the same uniform architecture. You no longer need to learn
and master different API architectures to write your applications.
In most situations, you can effectively use all of the Microsoft programming
languages. Nevertheless, each programming language has its relative strengths and
you will want to understand the features unique to each language. The following
sections will help you choose the right programming language for your application.
Visual Basic .NET
Visual Basic .NET is the next generation of the Visual Basic language from Microsoft.
With Visual Basic you can build .NET applications, including Web services and
ASP.NET Web applications, quickly and easily. Applications made with Visual Basic are
built on the services of the common language runtime and take advantage of the
.NET Framework.
Visual Basic has many new and improved features such as inheritance, interfaces,
and overloading that make it a powerful object-oriented programming language.
Other new language features include free threading and structured exception
handling. Visual Basic fully integrates the .NET Framework and the common
language runtime, which together provide language interoperability, garbage
collection, enhanced security, and improved versioning support. A Visual Basic
support single inheritance and creates Microsoft intermediate language (MSIL) as
input to native code compilers.
Visual Basic is comparatively easy to learn and use, and Visual Basic has become the
programming language of choice for hundreds of thousands of developers over the
past decade. An understanding of Visual Basic can be leveraged in a variety of ways,
such as writing macros in Visual Studio and providing programmability in applications
such as Microsoft Excel, Access, and Word.
Visual Basic provides prototypes of some common project types, including:
• Windows Application.
• Class Library.
• Windows Control Library.
• ASP.NET Web Application.
• ASP.NET Web Service.
• Web Control Library.
• Console Application.
• Windows Service.
• Windows Service.
Visual C# .NET
Visual C# (pronounced C sharp) is designed to be a fast and easy way to create .NET
applications, including Web services and ASP.NET Web applications. Applications
written in Visual C# are built on the services of the common language runtime and
take full advantage of the .NET Framework.
C# is a simple, elegant, type-safe, object-oriented language recently developed by
Microsoft for building a wide range of applications. Anyone familiar with C and similar
languages will find few problems in adapting to C#. C# is designed to bring rapid
development to the C++ programmer without sacrificing the power and control that
are a hallmark of C and C++. Because of this heritage, C# has a high degree of
fidelity with C and C++, and developers familiar with these languages can quickly
become productive in C#. C# provides intrinsic code trust mechanisms for a high
level of security, garbage collection, and type safety. C# supports single inheritance
and creates Microsoft intermediate language (MSIL) as input to native code
compilers.
C# is fully integrated with the .NET Framework and the common language runtime,
which together provide language interoperability, garbage collection, enhanced
security, and improved versioning support. C# simplifies and modernizes some of the
more complex aspects of C and C++, notably namespaces, classes, enumerations,
overloading, and structured exception handling. C# also eliminates C and C++
features such as macros, multiple inheritance, and virtual base classes. For current
C++ developers, C# provides a powerful, high-productivity language alternative.
Visual C# provides prototypes of some common project types, including:
• Windows Application.
• Class Library.
• Windows Control Library.
• ASP.NET Web Application.
• ASP.NET Web Service.
• Web Control Library.
• Console Application.
• Windows Service.
The CLS is a set of rules that standardizes such things as data types and how objects
are exposed and interoperate. Visual Basic .NET adds several features that take
advantage of the CLS. Any CLS-compliant language can use the classes, objects, and
components you create in Visual Basic .NET. And you, as a Visual Basic user, can
access classes, components, and objects from other CLS-compliant programming
languages without worrying about language-specific differences such as data types.
CLS features used by Visual Basic .NET programs include assemblies, namespaces,
and attributes. These are the new features to be stated briefly:
Inheritance
Visual Basic .NET supports inheritance by allowing you to define classes that serve as
the basis for derived classes. Derived classes inherit and can extend the properties
and methods of the base class. They can also override inherited methods with new
implementations. All classes created with Visual Basic .NET are inheritable by default.
Because the forms you design are really classes, you can use inheritance to define
new forms based on existing ones.
Exception Handling
Visual Basic .NET supports structured exception handling, using an enhanced version
of the Try...Catch...Finally syntax supported by other languages such as C++.
Structured exception handling combines a modern control structure (similar to Select
Case or While) with exceptions, protected blocks of code, and filters. Structured
exception handling makes it easy to create and maintain programs with robust,
comprehensive error handlers.
Overloading
Overloading is the ability to define properties, methods, or procedures that have the
same name but use different data types. Overloaded procedures allow you to provide
as many implementations as necessary to handle different kinds of data, while giving
the appearance of a single, versatile procedure. Overriding Properties and Methods
The Overrides keyword allows derived objects to override characteristics inherited
from parent objects. Overridden members have the same arguments as the
members inherited from the base class, but different implementations. A member's
new implementation can call the original implementation in the parent class by
preceding the member name with MyBase.
Data Types
Visual Basic .NET introduces three new data types. The Char data type is an
unsigned 16-bit quantity used to store Unicode characters. It is equivalent to the
.NET Framework System. Char data type. The Short data type, a signed 16-bit
integer, was named Integer in earlier versions of Visual Basic. The Decimal data type
is a 96-bit signed integer scaled by a variable power of 10. In earlier versions of
Visual Basic, it was available only within a Variant.
Interfaces
Interfaces describe the properties and methods of classes, but unlike classes, do not
provide implementations. The Interface statement allows you to declare interfaces,
while the Implements statement lets you write code that puts the items described in
the interface into practice.
Delegates
Delegates objects that can call the methods of objects on your behalf are sometimes
described as type-safe, object-oriented function pointers. You can use delegates to
let procedures specify an event handler method that runs when an event occurs. You
can also use delegates with multithreaded applications. For details, see Delegates
and the AddressOf Operator.
Shared Members
Shared members are properties, procedures, and fields that are shared by all
instances of a class. Shared data members are useful when multiple objects need to
use information that is common to all. Shared class methods can be used without
first creating an object from a class.
References
References allow you to use objects defined in other assemblies. In Visual Basic .NET,
references point to assemblies instead of type libraries. For details, see References
and the Imports Statement. Namespaces Namespaces prevent naming conflicts by
organizing classes, interfaces, and methods into hierarchies.
Assemblies
Assemblies replace and extend the capabilities of type libraries by, describing all the
required files for a particular component or application. An assembly can contain one
or more namespaces.
Attributes
Attributes enable you to provide additional information about program elements. For
example, you can use an attribute to specify which methods in a class should be
exposed when the class is used as a XML Web service. Multithreading
Visual Basic .NET allows you to write applications that can perform multiple tasks
independently. A task that has the potential of holding up other tasks can execute on
a separate thread, a process known as multithreading. By causing complicated tasks
to run on threads that are separate from your user interface, multithreading makes
your applications more responsive to user input.
First of all, VB.NET provides managed code execution that runs under the Common
Language Runtime (CLR), resulting in robust, stable and secure applications. All
features of the .NET framework are readily available in VB.NET.
VB.NET is totally object oriented. This is a major addition that VB6 and other earlier
releases didn't have.
The .NET framework comes with ADO.NET, which follows the disconnected paradigm,
i.e. once the required records are fetched the connection no longer exists. It also
retrieves the records that are expected to be accessed in the immediate future. This
enhances Scalability of the application to a great extent.
VB.NET uses XML to transfer data between the various layers in the DNA Architecture
i.e. data are passed as simple text strings.
Error handling has changed in VB.NET. A new Try-Catch-Finally block has been
introduced to handle errors and exceptions as a unit, allowing appropriate action to
be taken at the place the error occurred thus discouraging the use of ON ERROR
GOTO statement. This again credits to the maintainability of the code.
Another great feature added to VB.NET is free threading against the VB single-
threaded apartment feature. In many situations developers need spawning of a new
thread to run as a background process and increase the usability of the application.
VB.NET allows developers to spawn threads wherever they feel like, hence giving
freedom and better control on the application.
Security has become more robust in VB.NET. In addition to the role-based security in
VB6, VB.NET comes with a new security model, Code Access security. This security
controls on what the code can access. For example you can set the security to a
component such that the component cannot access the database. This type of
security is important because it allows building components that can be trusted to
various degrees.
The CLR takes care of garbage collection i.e. the CLR releases resources as soon as
an object is no more in use. This relieves the developer from thinking of ways to
manage memory. CLR does this for them.
14. Using ActiveX Control in .Net
ActiveX control is a special type of COM component that supports a User Interface.
Using ActiveX Control in your .Net Project is even easier than using COM component.
They are bundled usually in .ocx files. Again a proxy assembly is made by .Net utility
AxImp.exe (which we will see shortly) which your application (or client) uses as if it
is a .Net control or assembly.
Making Proxy Assembly For ActiveX Control: First, a proxy assembly is made using
AxImp.exe (acronym for ActiveX Import) by writing following command on Command
Prompt:
C:>AxImp C:MyProjectsMyControl.ocx
This command will make two dlls, e.g., in case of above command
MyControl.dll
AxMyControl.dll
The first file MyControl.dll is a .Net assembly proxy, which allows you to reference
the ActiveX as if it were non-graphical object.
The second file AxMyControl.dll is the Windows Control, which allows u to use the
graphical aspects of activex control and use it in the Windows Form Project.
Adding Reference of ActiveX Proxy Assembly in your Project Settings: To add a
reference of ActiveX Proxy Assembly in our Project, do this:
o Select ProjectàAdd Reference (Select Add Reference from Project Menu).
o This will show you a dialog box, select .Net tab from the top of window.
o Click Browse button on the top right of window.
o Select the dll file for your ActiveX Proxy Assembly (which is MyControl.dll) and click
OK o Your selected component is now shown in the ‘Selected Component’ List Box.
Click OK again Some More On Using COM or ActiveX in .Net
.Net only provides wrapper class or proxy assembly (Runtime Callable Wrapper or
RCW) for COM or activeX control. In the background, it is actually delegating the
tasks to the original COM, so it does not convert your COM/activeX but just imports
them.
A good thing about .Net is that when it imports a component, it also imports the
components that are publically referenced by that component. So, if your
component, say MyDataAcsess.dll references ADODB.dll then .Net will automatically
import that COM component too!
The Visual Studio.NET does surprise you in a great deal when u see that it is applying
its intellisense (showing methods, classes, interfaces, properties when placing dot)
even on your imported COM components!!!! Isn’t it a magic or what?
When accessing thru RCW, .Net client has no knowledge that it is using COM
component, it is presented just as another C# assembly.
U can also import COM component thru command prompt (for reference see
Professional C# by Wrox) U can also use your .Net components in COM, i.e., export
your .net components (for reference see Professional C# by Wrox)
Machine configuration file: The machine.config file contains settings that apply to the
entire computer. This file is located in the %runtime install path%Config directory.
There is only one machine.config file on a computer. The Machine.Config file found in
the "CONFIG" subfolder of your .NET Framework install directory
(c:WINNTMicrosoft.NETFramework{Version Number}CONFIG on Windows 2000
installations). The machine.config, which can be found in the directory
$WINDIR$Microsoft.NETFrameworkv1.0.3705CONFIG, is an XML-formatted
configuration file that specifies configuration options for the machine. This file
contains, among many other XML elements, a browserCaps element. Inside this
element are a number of other elements that specify parse rules for the various
User-Agents, and what properties each of these parsings supports.
For example, to determine what platform is used, a filter element is used that
specifies how to set the platform property based on what platform name is found in
the User-Agent string. Specifically, the machine.config file contains:
platform=Win95
platform=Win98
platform=WinNT
...
That is, if in the User-Agent string the string "Windows 95" or "Win95" is found, the
platform property is set to Win95. There are a number of filter elements in the
browserCaps element in the machine.config file that define the various properties for
various User-Agent strings.
Hence, when using the Request.Browser property to determine a user's browser
features, the user's agent string is matched up to particular properties in the
machine.config file. The ability for being able to detect a user's browser's capabilities,
then, is based upon the honesty in the browser's sent User-Agent string. For
example, Opera can be easily configured to send a User-Agent string that makes it
appear as if it's IE 5.5. In this case from the Web server's perspective (and, hence,
from your ASP.NET Web page's perspective), the user is visiting using IE 5.5, even
though, in actuality, he is using Opera.
In classic ASP all Web site related information was stored in the metadata of IIS. This
had the disadvantage that remote Web developers couldn't easily make Web-site
configuration changes. For example, if you want to add a custom 404 error page, a
setting needs to be made through the IIS admin tool, and you're Web host will likely
charge you a flat fee to do this for you. With ASP.NET, however, these settings are
moved into an XML-formatted text file (Web.config) that resides in the Web site's
root directory. Through Web.config you can specify settings like custom 404 error
pages, authentication and authorization settings for the Web sitempilation options for
the ASP.NET Web pages, if tracing should be enabled, etc.
The Web.config file is an XML-formatted file. At the root level is the tag. Inside this
tag you can add a number of other tags, the most common and useful one being the
system.web tag, where you will specify most of the Web site configuration
parameters. However, to specify application-wide settings you use the tag.
For example, if we wanted to add a database connection string parameter we could
have a Web.config file like so.
ADO uses Recordsets and cursors to access and modify data. Because of its inherent
design, Recordset can impact performance on the server side by tying up valuable
resources. In addition, COM marshalling - an expensive data conversion process - is
needed to transmit a Recordset. ADO.NET addresses three important needs that ADO
doesn't address:
Now VB.NET is object-oriented language. The following are some of the differences:
Data Type Changes
The .NET platform provides Common Type System to all the supported languages.
This means that all the languages must support the same data types as enforced by
common language runtime. This eliminates data type incompatibilities between
various languages. For example on the 32-bit Windows platform, the integer data
type takes 4 bytes in languages like C++ whereas in VB it takes 2 bytes. Following
are the main changes related to data types in VB.NET:
. Under .NET the integer data type in VB.NET is also 4 bytes in size.
. VB.NET has no currency data type. Instead it provides decimal as a replacement.
. VB.NET introduces a new data type called Char. The char data type takes 2 bytes
and can store Unicode characters.
. VB.NET do not have Variant data type. To achieve a result similar to variant type
you can use Object data type. (Since every thing in .NET including primitive data
types is an object, a variable of object type can point to any data type).
. In VB.NET there is no concept of fixed length strings.
. In VB6 we used the Type keyword to declare our user-defined structures. VB.NET
introduces the structure keyword for the same purpose.
Declaring Variables
Consider this simple example in VB6:
Dim x,y as integer
In this example VB6 will consider x as variant and y as integer, which is somewhat
odd behavior. VB.NET corrects this problem, creating both x and y as integers.
Furthermore, VB.NET allows you to assign initial values to the variables in the
declaration statement itself:
Dim str1 as string = Hello
VB.NET also introduces Read-Only variables. Unlike constants Read-Only variables
can be declared without initialization but once you assign a value to it, it cannot be
changes.
Initialization here
Dim readonly x as integer
In later code
X=100
Now x can’t be changed
X=200 *********** Error **********
Property Syntax
In VB.NET, we anymore don't have separate declarations for Get and Set/Let. Now,
everything is done in a single property declaration. This can be better explained by
the following example.
Public [ReadOnly | WriteOnly] Property PropertyName as Datatype
Get
Return m_var
End Get
Set
M_var = value
End Set
End Property
Example:
Private _message as String
Public Property Message As String
Get
Return _message
End Get
Set
_message = Value
End Set
End Property
ByVal is the default - This is a crucial difference betwen VB 6.0 and VB.NET, where
the default in VB 6.0 was by reference. But objects are still passed by reference.
Invoking Subroutines In previous versions of VB, only functions required the use of
parentheses around the parameter list. But in VB.NET all function or subroutine calls
require parentheses around the parameter list. This also applies, even though the
parameter list is empty.
User-Defined Types - VB.NET does away with the keyword Type and replaces it with
the keyword Structure
Public Structure Student
Dim strName as String
Dim strAge as Short
End Structure
Procedures and Functions
In VB6 all the procedure parameters are passed by reference (ByRef) by default. In
VB.NET they are passed by value (ByVal) by default. Parantheses are required for
calling procedures and functions whether they accept any parameters or not. In VB6
functions returned values using syntax like: FuntionName = return_value. In VB.NET
you can use the Return keyword (Return return_value) to return values or you can
continue to use the older syntax, which is still valid.
Scoping VB.NET now supports block-level scoping of variables. If your programs
declare all of the variables at the beginning of the function or subroutine, this will not
be a problem. However, the following VB 6.0 will cause an issue while upgrading to
VB .NET
Do While objRs.Eof
Dim J as Integer
J=0
If objRs("flag")="Y" then
J=1
End If
objRs.MoveNext
Wend
If J Then
Msgbox "Flag is Y"
End If
In the above example the variable J will become out of scope just after the loop,
since J was declared inside the While loop.
Exception Handling
The most wanted feature in earlier versions of VB was its error handling mechanism.
The older versions relied on error handlers such as "On Error GoTo and On Error
Resume Next. VB.NET provides us with a more stuructured approach. The new block
structure allows us to track the exact error at the right time. The new error handling
mechanism is refered to as Try...Throw...Catch...Finally. The following example will
explain this new feature.
Sub myOpenFile()
Try
Open "myFile" For Output As #1
Write #1, myOutput
Catch
Kill "myFile"
Finally
Close #1
End try
End Sub
The keyword SET is gone - Since everything in VB.NET is an object. So the keyword
SET is not at all used to differentiate between a simple variable assignment and an
object assignment. So, if you have the following statement in VB 6.0
Set ObjConn = Nothing
Should be replaced as
ObjConn = Nothing.
Constructor and Destructor
The constructor procedure is one of the many new object-oriented features of
VB.NET. The constructor in VB.NET replaces the Class_Initialize in VB 6.0. All
occurance of Class_Initialize in previous versions of VB should now be placed in a
class constructor. In VB.NET, a constructor is added to a class by adding a procedure
called New. We can also create a class destructor, which is equivalent to
Class_Terminate event in VB 6.0, by adding a sub-procedure called Finalize to our
class. Usage of Return In VB.NET, we can use the keyword return to return a value
from any function. In previous versions, we used to assign the value back with the
help of the function name itself. The following example explains this:
Public Function Sum (intNum1 as Integer, intNum2 as Integer) as Integer
Dim intSum as Integer
intSum = intNum1 + intNum2
Return intSum
End Function
Static Methods
VB.NET now allows you to create static methods in your classes. Static methods are
methods that can be called without requiring the developer to create instance of the
class. For example, if you had a class named Foo with the non-static method
NonStatic() and the static method Static(), you could call the Static() method like so:
Foo.Static()
However, non-static methods require than an instance of the class be created, like
so:
Create an instance of the Foo class
Dim objFoo as New Foo()
Execute the NonStatic() method
ObjFoo.NonStatic()
To create a static method in a VB.NET, simply prefix the method definition with the
keyword Shared.
An assembly manifest contains all the metadata needed to specify the assembly's
version requirements and security identity, and all metadata needed to define the
scope of the assembly and resolve references to resources and classes. The
assembly manifest can be stored in either a PE (Portable Executable) file (an .exe or
.dll) with Microsoft intermediate language (MSIL) code or in a standalone PE
(Portable Executable) file that contains only assembly manifest information. The
following table shows the information contained in the assembly manifest. The first
four items the assembly name, version number, culture, and strong name
information make up the assembly's identity. Assembly name: A text string
specifying the assembly's name. Version number: A major and minor version
number, and a revision and build number. The common language runtime uses these
numbers to enforce version policy.
Culture: Information on the culture or language the assembly supports. This
information should be used only to designate an assembly as a satellite assembly
containing culture- or language-specific information. (An assembly with culture
information is automatically assumed to be a satellite assembly.) Strong name
information: The public key from the publisher if the assembly has been given a
strong name. List of all files in the assembly: A hash of each file contained in the
assembly and a file name. Note that all files that make up the assembly must be in
the same directory as the file containing the assembly manifest. Type reference
information: Information used by the runtime to map a type reference to the file that
contains its declaration and implementation. This is used for types that are exported
from the assembly.
Information on referenced assemblies: A list of other assemblies that are statically
referenced by the assembly. Each reference includes the dependent assembly's
name, assembly metadata (version, culture, operating system, and so on), and
public key, if the assembly is strong named.
You can create a key pair using the Strong Name tool (Sn.exe). Key pair files usually
have an .snk extension. To create a key pair At the command prompt, type the
following command:
sn k
In this command, file name is the name of the output file containing the key pair.
The following example creates a key pair called sgKey.snk.
sn -k sgKey.snk
When u compile a program using command line, u add the references using /r
switch. When you compile a program using Visual Studio, it adds those references to
our assembly, which are added using "Add Reference" dialog box. While "using"
statement facilitates us to use classes without using their fully qualified names.
For example: if u have added a reference to "System.Data.SqlClient" using "Add
Reference" dialog box then u can use SqlConnection class like this:
System.Data.SqlClient.SqlConnection
But if u add a "using System.Data.SqlClient" statement at the start of ur code then u
can directly use SqlConnection class.
On the other hand if u add a reference using "using System.Data.SqlClient"
statement, but don't add it using "Add Reference" dialog box, Visual Studio will give
error message while we compile the program.
Managed code is code that is written to target the services of the Common Language
Runtime. In order to target these services, the code must provide a minimum level
of information (metadata) to the runtime. All C#, Visual Basic .NET, and JScript .NET
code is managed by default. Visual Studio .NET C++ code is not managed by default,
but the compiler can produce managed code by specifying a command-line switch
(/CLR). Closely related to managed code is managed data--data that is allocated and
de- allocated by the Common Language Runtime's garbage collector. C#, Visual
Basic, and JScript .NET data is managed by default. C# data can, however, be
marked as unmanaged through the use of special keywords. Visual Studio .NET C++
data is unmanaged by default (even when using the /CLR switch), but when using
Managed Extensions for C++, a class can be marked as managed using the __gc
keyword. As the name suggests, this means that the memory for instances of the
class is managed by the garbage collector. In addition, the class becomes a full
participating member of the .NET Framework community, with the benefits and
restrictions that it brings. An example of a benefit is proper interoperability with
classes written in other languages (for example, a managed C++ class can inherit
from a Visual Basic class). An example of a restriction is that a managed class can
only inherit from one base class.
CTS defines all of the basic types that can be used in the .NET Framework and the
operations performed on those type.
All this time we have been talking about language interoperability, and .NET Class
Framework. None of this is possible without all the language sharing the same data
types. What this means is that an int should mean the same in VB, VC++, C# and all
other .NET compliant languages. This is achieved through introduction of Common
Type System (CTS).
CLS is the collection of the rules and constraints that every language (that seeks to
achieve .NET compatibility) must follow. It is a subsection of CTS and it specifies how
it shares and extends one another libraries.
CLR is .NET equivalent of Java Virtual Machine (JVM). It is the runtime that converts
a MSIL code into the host machine language code, which is then executed
appropriately. The CLR is the execution engine for .NET Framework applications. It
provides a number of services, including:
- Code management (loading and execution)
> - Application memory isolation
- Verification of type safety
- Conversion of IL to native code.
- Access to metadata (enhanced type informmatiion)
- Managing memory for managed objects
- Enforcement of code access security
- Exception handling, including cross-langguagge exceptions
- Interoperation between managed code, COMM obbjects, and pre-existing DLL's
(unmanaged code and data)
- Automation of object layout
- Support for developer services (profilinng, debugging, and so on).
Attributes are declarative tags in code that insert additional metadata into an
assembly. There exist two types of attributes in the .NET Framework: Predefined
attributes such as AssemblyVersion, which already exist and are accessed through
the Runtime Classes; and custom attributes, which you write yourself by extending
the System.Attribute class.
Assemblies are made up of IL code modules and the metadata that describes them.
Although programs may be compiled via an IDE or the command line, in fact, they
are simply translated into IL, not machine code. The actual machine code is not
generated until the function that requires it is called. This is the just-in-time, or JIT,
compilation feature of .NET. JIT compilation happens at runtime for a variety of
reasons, one of the most ambitious being Microsoft's desire for cross-platform .NET
adoption. If a CLR is built for another operating system (UNIX or Mac), the same
assemblies will run in addition to the Microsoft platforms. The hope is that .NET
assemblies are write-once-run-anywhere applications. This is a .NET feature that
works behind-the-scenes, ensuring that developers are not limited to writing
applications for one single line of products. No one has demonstrated whether or not
this promise will ever truly materialize. CTS/CLS
The MSIL Instruction Set Specification is included with the .NET SDK, along with the
IL Assembly Language Programmers Reference. If a developer wants to write custom
.NET programming languages, these are the necessary specifications and syntax. The
CTS and CLS define the types and syntaxes that every .NET language needs to
embrace. An application may not expose these features, but it must consider them
when communicating through IL.
As most of you know that .Net does not encourage the development of COM
components and provides a different solution to making reusable components
through Assemblies. But, there are a lot of COM components present which our .Net
application might need to use. Fortunately, .Net provides an extremely simple
approach to achieve this. This is achieved by using ‘Wrapper Classes’ and ‘Proxy
Components’. .Net wraps the COM component into .Net assembly technically called
‘Runtime Callable Wrapper’ or RCW. Then u can call and use your COM component
just as a .Net (or C#, if u are using C#) Assembly.
A web service is a software component that exposes itself through the open
communication channels of the Internet. Applications running on remote machines,
on potentially different platforms, can access these components in a language and
platform-independent manner. A Web Service is a group of functions, packaged
together for use in a common framework throughout a network.
A delegate acts like a strongly type function pointer. Delegates can invoke the
methods that they reference without making explicit calls to those methods.
Delegate is an entity that is entrusted with the task of representation, assign or
passing on information. In code sense, it means a Delegate is entrusted with a
Method to report information back to it when a certain task (which the Method
expects) is accomplished outside the Method's class.
A .NET programming language (C#, VB.NET, J# etc.) does not compile into
executable code; instead it compiles into an intermediate code called Microsoft
Intermediate Language (MSIL). As a programmer one need not worry about the
syntax of MSIL - since our source code in automatically converted to MSIL. The MSIL
code is then send to the CLR (Common Language Runtime) that converts the code to
machine language, which is, then run on the host machine. MSIL is similar to Java
Byte code. MSIL is the CPU-independent instruction set into which .NET Framework
programs are compiled. It contains instructions for loading, storing, initializing, and
calling methods on objects. Combined with metadata and the common type system,
MSIL allows for true cross- language integration Prior to execution, MSIL is converted
to machine code. It is not interpreted.
A delegate acts like a strongly type function pointer. Delegates can invoke the
methods that they reference without making explicit calls to those methods.
Delegate is an entity that is entrusted with the task of representation, assign or
passing on information. In code sense, it means a Delegate is entrusted with a
Method to report information back to it when a certain task (which the Method
expects) is accomplished outside the Method's class.
A .NET programming language (C#, VB.NET, J# etc.) does not compile into
executable code; instead it compiles into an intermediate code called Microsoft
Intermediate Language (MSIL). As a programmer one need not worry about the
syntax of MSIL - since our source code in automatically converted to MSIL. The MSIL
code is then send to the CLR (Common Language Runtime) that converts the code to
machine language, which is, then run on the host machine. MSIL is similar to Java
Byte code. MSIL is the CPU-independent instruction set into which .NET Framework
programs are compiled. It contains instructions for loading, storing, initializing, and
calling methods on objects. Combined with metadata and the common type system,
MSIL allows for true cross- language integration Prior to execution, MSIL is converted
to machine code. It is not interpreted.
Bill Gates delivered a keynote at Forum 2000, held June 22, 2000, outlining the .NET
'vision'. The July 2000 PDC had a number of sessions on .NET technology, and
delegates were given CDs containing a pre-release version of the .NET
framework/SDK and Visual Studio.NET.
The final versions of the 1.0 SDK and runtime were made publicly available around
6pm PST on 15-Jan-2002. At the same time, the final version of Visual Studio.NET
was made available to MSDN subscribers.
.NET 1.1 was released in April 2003, and was mostly bug fixes for 1.0.
.NET 2.0 was released to MSDN subscribers in late October 2005, and was officially
launched in early November.
1.4 What operating systems does the .NET Framework run on?
The runtime supports Windows Server 2003, Windows XP, Windows 2000, NT4 SP6a
and Windows ME/98. Windows 95 is not supported. Some parts of the framework do
not work on all platforms - for example, ASP.NET is only supported on XP and
Windows 2000/2003. Windows 98/ME cannot be used for development.
IIS is not supported on Windows XP Home Edition, and so cannot be used to host
ASP.NET. However, the ASP.NET Web Matrix web server does run on XP Home.
The .NET Compact Framework is a version of the .NET Framework for mobile devices,
running Windows CE or Windows Mobile.
The Mono project has a version of the .NET Framework that runs on Linux.
You can see the differences between the various Visual Studio versions here.
I don't know what they were thinking. They certainly weren't thinking of people using
search tools. It's meaningless marketing nonsense.
2. Terminology
2.2 What is the CTS, and how does it relate to the CLS?
CTS = Common Type System. This is the full range of types that the .NET runtime
understands. Not all .NET languages support all the types in the CTS.
CLS = Common Language Specification. This is a subset of the CTS which all .NET
languages are expected to support. The idea is that any program which uses CLS-
compliant types can interoperate with any .NET program written in any language.
This interop is very fine-grained - for example a VB.NET class can inherit from a C#
class.
Substitute 'Java' for 'C#' in the quote above, and you'll see that the statement still
works pretty well :-).
If you are a C++ programmer, you might like to check out my C# FAQ.
The term 'managed' is the cause of much confusion. It is used in various places
within .NET, meaning slightly different things.
Managed code: The .NET framework provides several core run-time services to the
programs that run within it - for example exception handling and security. For these
services to work, the code must provide a minimum level of information to the
runtime. Such code is called managed code.
Managed data: This is data that is allocated and freed by the .NET runtime's garbage
collector.
All .NET compilers produce metadata about the types defined in the modules they
produce. This metadata is packaged along with the module (modules in turn are
packaged together in assemblies), and can be accessed by a mechanism called
reflection. The System.Reflection namespace contains classes that can be used to
interrogate the types for a module/assembly.
An important aspect of assemblies is that they are part of the identity of a type. The
identity of a type is the assembly that houses it combined with the type name. This
means, for example, that if assembly A exports a type called T, and assembly B
exports a type called T, the .NET runtime sees these as two completely different
types. Furthermore, don't get confused between assemblies and namespaces -
namespaces are merely a hierarchical way of organising type names. To the runtime,
type names are type names, regardless of whether namespaces are used to organise
the names. It's the assembly plus the typename (regardless of whether the type
name belongs to a namespace) that uniquely indentifies a type to the runtime.
Assemblies are also important in .NET with respect to security - many of the security
restrictions are enforced at the assembly boundary.
Finally, assemblies are the unit of versioning in .NET - more on this below.
The simplest way to produce an assembly is directly from a .NET compiler. For
example, the following C# program:
public class CTest
{
public CTest() { System.Console.WriteLine( "Hello from CTest" ); }
}
You can then view the contents of the assembly by running the "IL Disassembler"
tool that comes with the .NET SDK.
Alternatively you can compile your source into modules, and then combine the
modules into an assembly using the assembly linker (al.exe). For the C# compiler,
the /target:module switch is used to generate a module instead of an assembly.
By searching directory paths. There are several factors which can affect the path
(such as the AppDomain host, and application configuration files), but for private
assemblies the search path is normally the application's directory and its sub-
directories. For shared assemblies, the search path is normally same as the private
assembly path plus the shared assembly cache.
Each assembly has a version number called the compatibility version. Also each
reference to an assembly (from another assembly) includes both the name and
version of the referenced assembly.
The version number has four numeric parts (e.g. 5.5.2.33). Assemblies with either of
the first two parts different are normally viewed as incompatible. If the first two
parts are the same, but the third is different, the assemblies are deemed as 'maybe
compatible'. If only the fourth part is different, the assemblies are deemed
compatible. However, this is just the default guideline - it is the version policy that
decides to what extent these rules are enforced. The version policy can be specified
via the application configuration file.
3.6 How can I develop an application that automatically updates itself from
the web?
For .NET 1.x, use the Updater Application Block. For .NET 2.x, use ClickOnce.
4. Application Domains
Win32 processes provide isolation by having distinct memory address spaces. This is
effective, but expensive. The .NET runtime enforces AppDomain isolation by keeping
control over the use of memory - all memory in the AppDomain is managed by the
.NET runtime, so the runtime can ensure that AppDomains do not access each
other's memory.
One non-obvious use of AppDomains is for unloading types. Currently the only way
to unload a .NET type is to destroy the AppDomain it is loaded into. This is
particularly useful if you create and destroy types on-the-fly via reflection.
AppDomains are usually created by hosts. Examples of hosts are the Windows Shell,
ASP.NET and IE. When you run a .NET application from the command-line, the host is
the Shell. The Shell creates a new AppDomain for every application.
5. Garbage Collection
5.2 Is it true that objects don't always get destroyed immediately when the
last reference goes away?
Yes. The garbage collector offers no guarantees about the time when an object will
be destroyed and its memory reclaimed.
There was an interesting thread on the DOTNET list, started by Chris Sells, about the
implications of non-deterministic destruction of objects in C#. In October 2000,
Microsoft's Brian Harry posted a lengthy analysis of the problem. Chris Sells'
response to Brian's posting is here.
Because of the garbage collection algorithm. The .NET garbage collector works by
periodically running through a list of all the objects that are currently being
referenced by an application. All the objects that it doesn't find during this search are
ready to be destroyed and the memory reclaimed. The implication of this algorithm is
that the runtime doesn't get notified immediately when the final reference on an
object goes away - it only finds out during the next 'sweep' of the heap.
Futhermore, this type of algorithm works best by performing the garbage collection
sweep as rarely as possible. Normally heap exhaustion is the trigger for a collection
sweep.
It's certainly an issue that affects component design. If you have objects that
maintain expensive or scarce resources (e.g. database locks), you need to provide
some way to tell the object to release the resource when it is done. Microsoft
recommend that you provide a method called Dispose() for this purpose. However,
this causes problems for distributed objects - in a distributed system who calls the
Dispose() method? Some form of reference-counting or ownership-management
mechanism is needed to handle distributed objects - unfortunately the runtime offers
no help with this.
5.5 Should I implement Finalize on my class? Should I implement
IDisposable?
This issue is a little more complex than it first appears. There are really two
categories of class that require deterministic destruction - the first category
manipulate unmanaged types directly, whereas the second category manipulate
managed types that require deterministic destruction. An example of the first
category is a class with an IntPtr member representing an OS file handle. An
example of the second category is a class with a System.IO.FileStream member.
For the first category, it makes sense to implement IDisposable and override Finalize.
This allows the object user to 'do the right thing' by calling Dispose, but also provides
a fallback of freeing the unmanaged resource in the Finalizer, should the calling code
fail in its duty. However this logic does not apply to the second category of class,
with only managed resources. In this case implementing Finalize is pointless, as
managed member objects cannot be accessed in the Finalizer. This is because there
is no guarantee about the ordering of Finalizer execution. So only the Dispose
method should be implemented. (If you think about it, it doesn't really make sense
to call Dispose on member objects from a Finalizer anyway, as the member object's
Finalizer will do the required cleanup.)
For classes that need to implement IDisposable and override Finalize, see Microsoft's
documented pattern.
Note that some developers argue that implementing a Finalizer is always a bad idea,
as it hides a bug in your code (i.e. the lack of a Dispose call). A less radical approach
is to implement Finalize but include a Debug.Assert at the start, thus signalling the
problem in developer builds but allowing the cleanup to occur in release builds.
A little. For example the System.GC class exposes a Collect method, which forces the
garbage collector to collect all unreferenced objects immediately.
Also there is a gcConcurrent setting that can be specified via the application
configuration file. This specifies whether or not the garbage collector performs some
of its collection activities on a separate thread. The setting only applies on multi-
processor machines, and defaults to true.
5.7 How can I find out what the garbage collector is doing?
Lots of interesting statistics are exported from the .NET runtime via the '.NET CLR
xxx' performance counters. Use Performance Monitor to view them.
The lapsed listener problem is one of the primary causes of leaks in .NET
applications. It occurs when a subscriber (or 'listener') signs up for a publisher's
event, but fails to unsubscribe. The failure to unsubscribe means that the publisher
maintains a reference to the subscriber as long as the publisher is alive. For some
publishers, this may be the duration of the application.
This situation causes two problems. The obvious problem is the leakage of the
subscriber object. The other problem is the performance degredation due to the
publisher sending redundant notifications to 'zombie' subscribers.
There are at least a couple of solutions to the problem. The simplest is to make sure
the subscriber is unsubscribed from the publisher, typically by adding an
Unsubscribe() method to the subscriber. Another solution, documented here by
Shawn Van Ness, is to change the publisher to use weak references in its subscriber
list.
It's very unintuitive, but the runtime can decide that an object is garbage much
sooner than you expect. More specifically, an object can become garbage while a
method is executing on the object, which is contrary to most developers'
expectations. Chris Brumme explains the issue on his blog. I've taken Chris's code
and expanded it into a full app that you can play with if you want to prove to yourself
that this is a real problem:
using System;
using System.Runtime.InteropServices;
class Win32
{
[DllImport("kernel32.dll")]
public static extern IntPtr CreateEvent( IntPtr lpEventAttributes,
bool bManualReset,bool bInitialState, string lpName);
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll")]
public static extern bool SetEvent(IntPtr hEvent);
}
class EventUser
{
public EventUser()
{
hEvent = Win32.CreateEvent( IntPtr.Zero, false, false, null );
}
~EventUser()
{
Win32.CloseHandle( hEvent );
Console.WriteLine("EventUser finalized");
}
IntPtr hEvent;
}
class App
{
static void Main(string[] args)
{
EventUser eventUser = new EventUser();
eventUser.UseEvent();
}
}
If you run this code, it'll probably work fine, and you'll get the following output:
SetEvent succeeded
EventDemo finalized
(Note that you need to use a release build to reproduce this problem.)
6. Serialization
6.2 Does the .NET Framework have in-built support for serialization?
There are two separate mechanisms provided by the .NET class library -
XmlSerializer and SoapFormatter/BinaryFormatter. Microsoft uses XmlSerializer for
Web Services, and SoapFormatter/BinaryFormatter for remoting. Both are available
for use in your own code.
It depends. XmlSerializer has severe limitations such as the requirement that the
target class has a parameterless constructor, and only public read/write properties
and fields can be serialized. However, on the plus side, XmlSerializer has good
support for customising the XML document that is produced or consumed.
XmlSerializer's features mean that it is most suitable for cross-platform work, or for
constructing objects from existing XML documents.
Look at the InnerException property of the exception that is thrown to get a more
specific error message.
7. Attributes
There are at least two types of .NET attribute. The first type I will refer to as a
metadata attribute - it allows some data to be attached to a class or method. This
data becomes part of the metadata for the class, and (like other class metadata) can
be accessed via reflection. An example of a metadata attribute is [serializable], which
can be attached to a class and means that instances of the class can be serialized.
[serializable] public class CTest {}
The other type of attribute is a context attribute. Context attributes use a similar
syntax to metadata attributes but they are fundamentally different. Context
attributes provide an interception mechanism whereby instance activation and
method calls can be pre- and/or post-processed. If you have encountered Keith
Brown's universal delegator you'll be familiar with this idea.
Yes. Simply derive a class from System.Attribute and mark it with the AttributeUsage
attribute. For example:
[AttributeUsage(AttributeTargets.Class)]
public class InspiredByAttribute : System.Attribute
{
public string InspiredBy;
class CApp
{
public static void Main()
{
object[] atts = typeof(CTest).GetCustomAttributes(true);
CAS is the part of the .NET security model that determines whether or not code is
allowed to run, and what resources it can use when it is running. For example, it is
CAS that will prevent a .NET web applet from formatting your hard disk.
The CAS security policy revolves around two key concepts - code groups and
permissions. Each .NET assembly is a member of a particular code group, and each
code group is granted the permissions specified in a named permission set.
For example, using the default security policy, a control downloaded from a web site
belongs to the 'Zone - Internet' code group, which adheres to the permissions
defined by the 'Internet' named permission set. (Naturally the 'Internet' named
permission set represents a very restrictive range of permissions.)
Microsoft defines some default ones, but you can modify these and even create your
own. To see the code groups defined on your system, run 'caspol -lg' from the
command-line. On my system it looks like this:
Level = Machine
Code Groups:
Note the hierarchy of code groups - the top of the hierarchy is the most general ('All
code'), which is then sub-divided into several groups, each of which in turn can be
sub-divided. Also note that (somewhat counter-intuitively) a sub-group can be
associated with a more permissive permission set than its parent.
Use caspol. For example, suppose you trust code from www.mydomain.com and you
want it have full access to your system, but you want to keep the default restrictions
for all other internet sites. To achieve this, you would add a new code group as a
sub-group of the 'Zone - Internet' group, like this:
caspol -ag 1.3 -site www.mydomain.com FullTrust
Now if you run caspol -lg you will see that the new group has been added as group
1.3.1:
...
1.3. Zone - Internet: Internet
1.3.1. Site - www.mydomain.com: FullTrust
...
Note that the numeric label (1.3.1) is just a caspol invention to make the code
groups easy to manipulate from the command-line. The underlying runtime never
sees it.
Use caspol. If you are the machine administrator, you can operate at the 'machine'
level - which means not only that the changes you make become the default for the
machine, but also that users cannot change the permissions to be more permissive.
If you are a normal (non-admin) user you can still modify the permissions, but only
to make them more restrictive. For example, to allow intranet code to do what it
likes you might do this:
caspol -cg 1.2 FullTrust
Note that because this is more permissive than the default policy (on a standard
system), you should only do this at the machine level - doing it at the user level will
have no effect.
Yes. Use caspol -ap, specifying an XML file containing the permissions in the
permission set. To save you some time, here is a sample file corresponding to the
'Everything' permission set - just edit to suit your needs. When you have edited the
sample, add it to the range of available permission sets like this:
caspol -ap samplepermset.xml
Then, to apply the permission set to a code group, do something like this:
caspol -cg 1.3 SamplePermSet
8.7 I'm having some trouble with CAS. How can I troubleshoot the problem?
Caspol has a couple of options that might help. First, you can ask caspol to tell you
what code group an assembly belongs to, using caspol -rsg. Similarly, you can ask
what permissions are being applied to a particular assembly using caspol -rsp.
Yes. MS supply a tool called Ildasm that can be used to view the metadata and IL for
an assembly.
Yes, it is often relatively straightforward to regenerate high-level source from IL. Lutz
Roeder's Reflector does a very good job of turning IL into C# or VB.NET.
You can buy an IL obfuscation tool. These tools work by 'optimising' the IL in such a
way that reverse-engineering becomes much more difficult.
Of course if you are writing web services then reverse-engineering is not a problem
as clients do not have access to your IL.
Yes. Peter Drayton posted this simple example to the DOTNET mailing list:
.assembly MyAssembly {}
.class MyApp {
.method static void Main() {
.entrypoint
ldstr "Hello, IL!"
call void System.Console::WriteLine(class System.Object)
ret
}
}
Just put this into a file called hello.il, and then run ilasm hello.il. An exe assembly will
be generated.
Yes. A couple of simple examples are that you can throw exceptions that are not
derived from System.Exception, and you can have non-zero-based arrays.
This subject causes a lot of controversy, as you'll see if you read the mailing list
archives. Take a look at the following two threads:
http://discuss.develop.com/archives/wa.exe?A2=ind0007&L=DOTNET&D=0&P=6824
1
http://discuss.develop.com/archives/wa.exe?A2=ind0007&L=DOTNET&P=R60761
The bottom line is that .NET has its own mechanisms for type interaction, and they
don't use COM. No IUnknown, no IDL, no typelibs, no registry-based activation. This
is mostly good, as a lot of COM was ugly. Generally speaking, .NET allows you to
package and use components in a similar way to COM, but makes the whole thing a
bit easier.
Pretty much, for .NET developers. The .NET Framework has a new remoting model
which is not based on DCOM. DCOM was pretty much dead anyway, once firewalls
became widespread and Microsoft got SOAP fever. Of course DCOM will still be used
in interop scenarios.
Not immediately. The approach for .NET 1.0 was to provide access to the existing
COM+ services (through an interop layer) rather than replace the services with
native .NET ones. Various tools and attributes were provided to make this as painless
as possible. Over time it is expected that interop will become more seamless - this
may mean that some services become a core part of the CLR, and/or it may mean
that some services will be rewritten as managed code which runs on top of the CLR.
For more on this topic, search for postings by Joe Long in the archives - Joe is the
MS group manager for COM+. Start with this message:
http://discuss.develop.com/archives/wa.exe?A2=ind0007&L=DOTNET&P=R68370
Yes. COM components are accessed from the .NET runtime via a Runtime Callable
Wrapper (RCW). This wrapper turns the COM interfaces exposed by the COM
component into .NET-compatible interfaces. For oleautomation interfaces, the RCW
can be generated automatically from a type library. For non-oleautomation
interfaces, it may be necessary to develop a custom RCW which manually maps the
types exposed by the COM interface to .NET-compatible types.
Here's a simple example for those familiar with ATL. First, create an ATL component
which implements the following IDL:
import "oaidl.idl";
import "ocidl.idl";
[
object,
uuid(EA013F93-487A-4403-86EC-FD9FEE5E6206),
helpstring("ICppName Interface"),
pointer_default(unique),
oleautomation
]
[
uuid(F5E4C61D-D93A-4295-A4B4-2453D4A4484D),
version(1.0),
helpstring("cppcomserver 1.0 Type Library")
]
library CPPCOMSERVERLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
[
uuid(600CE6D9-5ED7-4B4D-BB49-E8D5D5096F70),
helpstring("CppName Class")
]
coclass CppName
{
[default] interface ICppName;
};
};
When you've built the component, you should get a typelibrary. Run the TLBIMP
utility on the typelibary, like this:
tlbimp cppcomserver.tlb
You now need a .NET client - let's use C#. Create a .cs file containing the following
code:
using System;
using CPPCOMSERVERLib;
Note that the compiler is being told to reference the DLL we previously generated
from the typelibrary using TLBIMP. You should now be able to run
csharpcomclient.exe, and get the following output on the console:
Name is bob
Yes. .NET components are accessed from COM via a COM Callable Wrapper (CCW).
This is similar to a RCW (see previous question), but works in the opposite direction.
Again, if the wrapper cannot be automatically generated by the .NET development
tools, or if the automatic behaviour is not desirable, a custom CCW can be
developed. Also, for COM to 'see' the .NET component, the .NET component must be
registered in the registry.
Here's a simple example. Create a C# file called testcomserver.cs and put the
following in it:
using System;
using System.Runtime.InteropServices;
namespace AndyMc
{
[ClassInterface(ClassInterfaceType.AutoDual)]
public class CSharpCOMServer
{
public CSharpCOMServer() {}
public void SetName( string name ) { m_name = name; }
public string GetName() { return m_name; }
private string m_name;
}
}
Now you need to create a client to test your .NET COM component. VBScript will do -
put the following in a file called comclient.vbs:
Dim dotNetObj
Set dotNetObj = CreateObject("AndyMc.CSharpCOMServer")
dotNetObj.SetName ("bob")
MsgBox "Name is " & dotNetObj.GetName()
And hey presto you should get a message box displayed with the text "Name is bob".
Yes. ATL will continue to be valuable for writing COM components for some time, but
it has no place in the .NET world.
11. Threads
In this case creating an instance of the MyThread class is sufficient to spawn the
thread and execute the MyThread.ThreadMain() method:
MyThread t = new MyThread( "Hello, world." );
t.WaitUntilFinished();
There are several options. First, you can use your own communication mechanism to
tell the ThreadStart method to finish. Alternatively the Thread class has in-built
support for instructing the thread to stop. The two principle methods are
Thread.Interrupt() and Thread.Abort(). The former will cause a
ThreadInterruptedException to be thrown on the thread when it next goes into a
WaitJoinSleep state. In other words, Thread.Interrupt is a polite way of asking the
thread to stop when it is no longer doing any useful work. In contrast,
Thread.Abort() throws a ThreadAbortException regardless of what the thread is
doing. Furthermore, the ThreadAbortException cannot normally be caught (though
the ThreadStart's finally method will be executed). Thread.Abort() is a heavy-handed
mechanism which should not normally be required.
11.4 How do I know when my thread pool work item has completed?
There is no way to query the thread pool for this information. You must put code into
the WaitCallback method to signal that it has completed. Events are useful for this.
Each object has a concurrency lock (critical section) associated with it. The
System.Threading.Monitor.Enter/Exit methods are used to acquire and release this
lock. For example, instances of the following class only allow one thread at a time to
enter method f():
class C
{
public void f()
{
try
{
Monitor.Enter(this);
...
}
finally
{
Monitor.Exit(this);
}
}
}
C# has a 'lock' keyword which provides a convenient shorthand for the code above:
class C
{
public void f()
{
lock(this)
{
...
}
}
}
Note that calling Monitor.Enter(myObject) does NOT mean that all access to
myObject is serialized. It means that the synchronisation lock associated with
myObject has been acquired, and no other thread can acquire that lock until
Monitor.Exit(o) is called. In other words, this class is functionally equivalent to the
classes above:
class C
{
public void f()
{
lock( m_object )
{
...
}
}
Actually, it could be argued that this version of the code is superior, as the lock is
totally encapsulated within the class, and not accessible to the user of the object.
Ian Griffiths has some interesting discussion on ReaderWriterLock here and here.
12. Tracing
Yes, in the System.Diagnostics namespace. There are two main classes that deal
with tracing - Debug and Trace. They both work in a similar way - the difference is
that tracing from the Debug class only works in builds that have the DEBUG symbol
defined, whereas tracing from the Trace class only works in builds that have the
TRACE symbol defined. Typically this means that you should use
System.Diagnostics.Trace.WriteLine for tracing that you want to work in debug and
release builds, and System.Diagnostics.Debug.WriteLine for tracing that you want to
work only in debug builds.
Yes. The Debug and Trace classes both have a Listeners property, which is a
collection of sinks that receive the tracing that you send via Debug.WriteLine and
Trace.WriteLine respectively. By default the Listeners collection contains a single sink,
which is an instance of the DefaultTraceListener class. This sends output to the
Win32 OutputDebugString() function and also the
System.Diagnostics.Debugger.Log() method. This is useful when debugging, but if
you're trying to trace a problem at a customer site, redirecting the output to a file is
more appropriate. Fortunately, the TextWriterTraceListener class is provided for this
purpose.
Here's how to use the TextWriterTraceListener class to redirect Trace output to a file:
Trace.Listeners.Clear();
FileStream fs = new FileStream( @"c:\log.txt", FileMode.Create,
FileAccess.Write );
Trace.Listeners.Add( new TextWriterTraceListener( fs ) );
Note the use of Trace.Listeners.Clear() to remove the default listener. If you don't do
this, the output will go to the file and OutputDebugString(). Typically this is not what
you want, because OutputDebugString() imposes a big performance hit.
Yes. You can write your own TraceListener-derived class, and direct all output
through it. Here's a simple example, which derives from TextWriterTraceListener (and
therefore has in-built support for writing to files, as shown above) and adds timing
information and the thread ID for each trace line:
class MyListener : TextWriterTraceListener
{
public MyListener( Stream s ) : base(s)
{
}
The beauty of this approach is that when an instance of MyListener is added to the
Trace.Listeners collection, all calls to Trace.WriteLine() go through MyListener,
including calls made by referenced assemblies that know nothing about the
MyListener class.
.NET remoting involves sending messages along channels. Two of the standard
channels are HTTP and TCP. TCP is intended for LANs only - HTTP can be used for
LANs or WANs (internet).
Support is provided for multiple message serializarion formats. Examples are SOAP
(XML-based) and binary. By default, the HTTP channel uses SOAP (via the .NET
runtime Serialization SOAP Formatter), and the TCP channel uses binary (via the
.NET runtime Serialization Binary Formatter). But either channel can use either
serialization format.
13.2 How can I get at the Win32 API from a .NET program?
Use P/Invoke. This uses similar technology to COM Interop, but is used to access
static DLL entry points instead of COM objects. Here is an example of C# calling the
Win32 MessageBox function:
using System;
using System.Runtime.InteropServices;
class MainApp
{
[DllImport("user32.dll", EntryPoint="MessageBox", SetLastError=true,
CharSet=CharSet.Auto)]
public static extern int MessageBox(int hWnd, String strMessage, String
strCaption, uint uiType);
An event is just a wrapper for a multicast delegate. Adding a public event to a class
is almost the same as adding a public multicast delegate field. In both cases,
subscriber objects can register for notifications, and in both cases the publisher
object can send notifications to the subscribers. However, a public multicast delegate
has the undesirable property that external objects can invoke the delegate,
something we'd normally want to restrict to the publisher. Hence events - an event
adds public methods to the containing class to add and remove receivers, but does
not make the invocation mechanism public.
Each instance of a reference type has two fields maintained by the runtime - a
method table pointer and a sync block. These are 4 bytes each on a 32-bit system,
making a total of 8 bytes per object overhead. Obviously the instance data for the
type must be added to this to get the overall size of the object. So, for example,
instances of the following class are 12 bytes each:
class MyInt
{
...
private int x;
}
However, note that with the current implementation of the CLR there seems to be a
minimum object size of 12 bytes, even for classes with no data (e.g. System.Object).
64-bit (x64) versions of Windows support both 32-bit and 64-bit processes, and
corresponding 32-bit and 64-bit versions of .NET 2.0. (.NET 1.1 is 32-bit only).
.NET 2.0 apps can either run as 32-bit processes or as 64-bit processes. The OS
decides which to use based on the PE header of the executable. The flags in the PE
header are controlled via the compiler /platform switch, which allows the target of
the app to be specified as 'x86', 'x64' or 'any cpu'. Normally you specify 'any cpu',
and your app will run as 32-bit on 32-bit Windows and 64-bit on 64-bit Windows.
However if you have some 32-bit native code in your app (loaded via COM interop,
for example), you will need to specify 'x86', which will force 64-bit Windows to load
your app in a 32-bit process. You can also tweak the 32-bit flag in the PE header
using the SDK corflags utility.
Some more explanation here:
http://blogs.msdn.com/gauravseth/archive/2006/03/07/545104.aspx
http://blogs.msdn.com/joshwil/archive/2005/04/08/406567.aspx
http://msdn.microsoft.com/netframework/programming/64bit/gettingstarted/
Generics are useful for writing efficient type-independent code, particularly where
the types might include value types. The obvious application is container classes, and
the .NET 2.0 class library includes a suite of generic container classes in the
System.Collections.Generic namespace. Here's a simple example of a generic
container class being used:
List<int> myList = new List<int>();
myList.Add( 10 );
Anonymous methods reduce the amount of code you have to write when using
delegates, and are therefore especially useful for GUI programming. Here's an
example
AppDomain.CurrentDomain.ProcessExit += delegate { Console.WriteLine("Process
ending ..."); };
Partial classes is a useful feature for separating machine-generated code from hand-
written code in the same class, and will therefore be heavily used by development
tools such as Visual Studio.
int m_size = 0;
}
The use of 'yield return' is rather strange at first sight. It effectively synthethises an
implementation of IEnumerator, something we had to do manually in .NET 1.x.
14.3 What's the problem with .NET generics?
.NET generics work great for container classes. But what about other uses? Well, it
turns out that .NET generics have a major limitation - they require the type
parameter to be constrained. For example, you cannot do this:
static class Disposer<T>
{
public static void Dispose(T obj) { obj.Dispose(); }
}
The C# compiler will refuse to compile this code, as the type T has not been
constrained, and therefore only supports the methods of System.Object. Dispose is
not a method on System.Object, so the compilation fails. To fix this code, we need to
add a where clause, to reassure the compiler that our type T does indeed have a
Dispose method
static class Disposer<T> where T : IDisposable
{
public static void Dispose(T obj) { obj.Dispose(); }
}
The problem is that the requirement for explicit contraints is very limiting. We can
use constraints to say that T implements a particular interface, but we can't dilute
that to simply say that T implements a particular method. Contrast this with C++
templates (for example), where no constraint at all is required - it is assumed (and
verified at compile time) that if the code invokes the Dispose() method on a type,
then the type will support the method.
In fact, after writing generic code with interface constraints, we quickly see that we
haven't gained much over non-generic interface-based programming. For example,
we can easily rewrite the Disposer class without generics:
static class Disposer
{
public static void Dispose( IDisposable obj ) { obj.Dispose(); }
}