.NET

advertisement
.NET
A Case Study for Interoperability
What is .NET ?
“[…] like the Solar System, .NET is huge. And it’s complex. And it’s
filled with black holes and other things that don’t always make
sense. Yet it turns out to be a fantastic system in which to develop
software applications.”
[Tim Patrick, An Introduction to .NET for Beginners]
•
A set of technologies for developing and using components to create:
– Windows Applications
– Web Forms
– Web Services
•
Supports the software lifecycle
–
–
–
–
Development
Debugging
Deployment
Maintenance
This course’s goal with .NET: a case study for language interoperability
Microsoft .NET Framework
Architecture Overview
• .NET: new runtime environment and comprehensive base class
library (FCL – Framework Class Library)
.NET-aware programming languages (C#, J#, VB, C++)
Common Language Specification
Base Class Library
Common Language Runtime
Operating System
Base Class Library Overwiev
• The .NET framework class library supplies a standard set of classes,
interfaces, and structures for any language targeting .NET CLR =>
simplifies multi-language development, effectively providing a
common language API
• Organized by namespaces.
• A namespace consists of many classes and sub-namespaces.
• General namespaces: the root namespace in the class library is the
System namespace, which contains many basic classes such as
Object, Console, and contains general sub-Namespaces such as IO,
Net, Remoting, etc.
• Application specific namespaces: define types that are used for
building specific application types: System.Web.Services,
System.Web.UI, System.Windows.Forms
• In order to use classes in a namespace a directive as using
<namespace> or import <namespace> must be included at the
beginning of code.
Some of the General Namespaces
from the Class Library
Namespace
Description
System
All the basic types used by every application
System.Collections
Types for managing collections of objects; includes the popular
collection types, such as stacks, queues, hash tables, and so on
System.IO
Types for doing stream I/O, walking directories and files
System.NET
Types for network communication
System.Reflection
Types that allow the inspection of metadata and late binding to
types and their members
System.Runtime.Remoting
Types that allow for types to be accessed remotely
System.Runtime.Serialization
Types that allow for instances of objects to be persisted and
regenerated from a Stream
System.Security
Types used for protecting data and resources
System.Threading
Types used for asynchronous operations and synchronizing
access to resources
Example: Using FCL in C#
// compile with csc ex1.cs
using System;
using System.Collections;
public class Program {
public static void Main() {
ArrayList myAL = new ArrayList();
myAL.Add( "one" );
myAL.Add( "two" );
myAL.Add( "three" );
Console.WriteLine( "myAL has {0} elements.", myAL.Count );
}
}
Example: Using FCL in J#
//compile with vjc ex1.jsl
import System.*;
import System.Collections.*;
public class Program
{
public static void main(String[] args)
{
ArrayList myAL = new ArrayList();
myAL.Add("one");
myAL.Add("two");
myAL.Add("three");
Console.WriteLine("myAL has {0} elements.",
(Int32) myAL.get_Count());
}
}
Example: Using FCL in CPP
//compile with cl /clr ex1.cpp
using namespace System;
using namespace System::Collections;
int main()
{
ArrayList myAL = gcnew ArrayList();
myAL.Add("one");
myAL.Add("two");
myAL.Add("three");
Console::WriteLine( "{0}",myAL.Count );
}
This courses goals with .NET
• A case study for interoperability: How
does .NET Architecture support
Interoperability
Interoperability problem
• Problem: Developer wants to write different modules of
an application in different languages
• Other solutions:
– Representation standards & Communication protocols: address
the issues of passing data types between different machines.
Data can be passed by inter process communication
mechanisms
– Using a language neutral Interface Description Language CORBA. Objects can call methods across language and process
boundaries.
– Binary standard: interoperability is assured at binary level –
standardized calling model - COM
– Disadvantages:
• Permits only simple communication, no implementation inheritance
between classes written in different languages
• Developer has to do special actions for interop (interface
descriptions)
Characteristics of the .NET solution
for interoperability
•
Consists of:
–
–
–
–
•
.NET managed code benefits from the runtime's support for language interoperability
in the following ways:
–
–
•
Common Type System and Common Language Specification: defines common types
and common features that have to be provided by all participating languages
Metadata: defines an uniform mechanism for storing and retrieving type information:
Compilers store type information as metadata, and the common language runtime uses this
information to provide services during execution;
MSIL: Intermediate Language: all code is compiled to MSIL, which is a high-level machine
code executed by the runtime
CLR: runtime can manage the execution of multilanguage applications because all type
information is stored and retrieved in the same way, regardless of the language the code was
written in.
Types can inherit implementation from other types, pass objects as arguments to another
type's methods, and call methods defined on other types, regardless of the language the
types are implemented in.
Debuggers, profilers, or other tools are required to understand only one environment —
the Microsoft intermediate language (MSIL) and metadata for the common language
runtime—and they can support any programming language that targets the runtime.
Bottom line: What about interoperability of .NET managed code with
unmanaged code ?
[MSDN: .NET Framework Developer's Guide: Language Interoperability Overview ]
Outline
•
•
•
•
•
•
Common Language Runtime
Managed Modules and Metadata
Assemblies
The Common Type System
The Common Language Specification
Examples of supported Multi-language
interoperability
• Interoperability with Unmanaged Code
CLR
• A runtime usable by different programming languages
– CLR executes MSIL - it has no idea which language was used
for the source code
• The features of the CLR are available to any and all
languages that target it
• Features supported by CLR:
– Just-in-time (JIT) compilers
• JIT compiles intermediary language (MSIL) into native code
–
–
–
–
–
–
Common Type System
Garbage collector
Permission and policy-based security
Exceptions
Threading
Reflection
Managed modules
•
•
Compilers that target the CLR produce Managed modules
Managed module: a standard Windows portable executable (PE) file that requires
the CLR to execute
–
–
End-users must have the CLR installed on their machine in order to execute any managed
modules
A managed module consists of MSIL code and metadata
[Richter] – fig.1.1
Parts of a Managed module
PE header
The standard Windows PE file header.
Indicates the type of file: GUI-EXE, CUI-EXE, or DLL. Has a timestamp indicating
when the file was built.
For modules that contain only IL code, the bulk of the information in the PE header
is ignored. For modules that contain native CPU code, this header contains
information about the native CPU code.
CLR header
Contains the information (interpreted by the CLR and utilities) that makes this a
managed module. The header includes the version of the CLR required, some
flags, the MethodDef metadata token of the managed module’s entry point method
(Main method), and the location/size of the module’s metadata, resources, strong
name,etc.
Metadata
Every managed module contains metadata tables. There are two main types of
tables: tables that describe the types and members defined in your source code
and tables that describe the types and members referenced by your source
code.
Conceptually metadata are a superset of IDL’s, but, unlike them, are embedded
with the code.
IL code
IL (Intermediate Language) Code that the compiler produced as it compiled the
source code. The CLR later compiles the IL into native CPU instructions
IL is a CPU-independent machine language. IL is much higher level than most
CPU machine languages: IL understands object types and has instructions that
create and initialize objects, call virtual methods on objects, and manipulate array
elements directly.
[Richter] – Table 1.1
Uses of metadata
• Metadata makes a module self-describing
• IntelliSense parses metadata to tell you what methods a
type offers and what parameters that method expects.
• The CLR’s code verification process uses metadata to
ensure that your code performs only “safe” operations.
• Metadata allows an object’s fields to be serialized into a
memory block, remoted to another machine, and then
deserialized, re-creating the object and its state on the
remote machine.
• Metadata allows the garbage collector to track the
lifetime of objects. For any object, the garbage collector
can determine the type of the object and, from the
metadata, know which fields within that object refer to
other objects.
Assemblies
•
An assembly is a logical grouping of one or
more managed modules and resource files.
– Single-file or multifile assemblies
•
An assembly is the logical unit of deployment,
and the smallest unit of reuse, security, and
versioning
– CLR works with assemblies rather than managed
modules
•
Each Assembly is defined by a Manifest:
– Metadata that describes the assembly (version,
contained files, resource files, dependencies, etc.)
Assemblies
[Richter] – fig.1.2
Assemblies Manifest Contents
• Manifest contains:
– Identity information
• Name, version number, culture, strong name
– List of files in the assembly
– Map of assembly types to files
– Dependencies
• Other assemblies used by this assembly
– Exported types
– Security permissions needed to run
Module Metadata Contents
• Each module metadata contains:
– Description of types
• Name, visibility, base class, interfaces
implemented
• Members (methods, fields, properties, events,
nested types)
– Custom attributes
• User-defined
• Compiler-defined
• Framework-defined
How to create an assembly
• Single-file assemblies: created with usual compiler
options
• The C# (csc) and J# (vjc) compilers produce an
assembly when you specify any of the following
command-line switches: /t[arget]:exe, /t[arget]:winexe,
or /t[arget]:library. All these switches cause the
compiler to generate a single PE file that contains the
manifest metadata tables. The resulting file is either a
CUI executable, a GUI executable, or a DLL,
respectively.
• The C++ compiler can produce managed or unmanaged
code. In order to produce managed code (an assembly)
use the /CLR switch
Example
// File Prog1.cs
using System;
public class Program {
public static void Main() {
Console.WriteLine( "Hi" );
}
}
•
•
•
•
•
Compile with: csc /t:exe Prog1.cs
Produces file Prog1.exe, that is a standard PE file of type Windows console
application
Prog1.exe is a single-file assembly (contains only one module)
You can (and usually do so) generate a single-file assembly from multiple files of
source-code:
– csc /target:library /out:lib.dll *.cs
Multifile assemblies refer to assemblies consisting of several IL modules (nothing
to do with the number of source files !) => later
IL Disassembler: ILDASM.EXE
• Allows you to inspect the metadata and disassembled IL code from
an assembly
• Example: ILDASM on Prog1.exe
Example: MSIL code for
Program::Main
Example: Metadata for Prog1.exe
• TypeDef:
– Specifies the types defined here: Program
– Type Program has 2 methods: Main and .ctor
• TypeRef:
– Specifies the types referenced by the module
- these can be implemented in the same
module (TypeRef), in another module
(ModuleRef) of the same assembly or in
another assembly (AssemblyRef)
Example: Manifest for Prog1.exe
Multifile assemblies
• [Richter] identifies 3 reasons to use multifile assemblies:
– You can partition your types among separate files, allowing for
files to be incrementally downloaded. Partitioning the types into
separate files also allows for partial or piecemeal packaging and
deployment for “shrinkwrapped” scenarios.
– You can add resource or data files to your assembly. For example,
you could have a type that calculates some insurance information. This
type might require access to some actuarial tables to make its
computations. Instead of embedding the actuarial tables in your source
code, you could use a tool (such as the assembly linker (AL.exe),
discussed later) so that the data file is considered to be part of the
assembly. By the way, this data file can be in any format
– You can create assemblies consisting of types implemented in
different programming languages. When you compile C# source
code, the compiler produces a module. When you compile Visual Basic
source code, the compiler produces a separate module. You can
implement some types in C#, some types in Visual Basic, and other
types in other languages. You can then use a tool to combine all these
modules into a single assembly. To developers using the assembly, the
assembly just contains a bunch of types; developers won’t even know
that different programming languages were used.
How to create a multifile assembly
•
•
Important: The Visual Studio .NET IDE doesn’t natively support the ability
for you to create multifile assemblies. If you want to create multifile
assemblies, you must resort to using command-line tools.
Generating a module:
– C# and J# compilers: /t[arget]:module
– C++ compiler: /CLR:NOASSEMBLY /LD
– This switch tells the compiler to produce a PE file that doesn’t contain the
manifest metadata tables. The PE file produced is always a DLL PE file, and this
file must be added to an assembly before the types within it can be accessed
•
•
Adding a module to an assembly: C# compiler supports the
/addmodule:module switch
Creating an assembly from several modules: Assembly linker tool AL:
– al /out:assembly /t:type netmodule1 netmodule2 …
•
Adding a resource file to an assembly:
– al /embed [resource]
– al /link [resource]
•
Example:
– we have 2 source code files: RarelyUsedTypes.cs and FrecventlyUsedTypes.cs
and want to build a 2-modules assembly
Multifile Assembly Example (v1)
•
Generating a multifile assembly consisting of 2 managed modules, one with a manifest:
csc /t:module RUT.cs
csc /out:JeffTypes.dll /t:library /addmodule:RUT.netmodule FUT.cs
[Richter – Fig. 2-1]
Multifile Assembly Example (v2)
•
Generating a multifile assembly consisting of 3 managed modules, one with a manifest:
csc /t:module RUT.cs
csc /t:module FUT.cs
al /out:JeffTypes.dll /t:library FUT.netmodule RUT.netmodule
[Richter – Fig. 2-3]
Assembly Version Resource
Information
• When AL or a compiler
produces a PE file assembly, it
also embeds a default
standard Win32 Version
resource
• It can be examined by viewing
the file’s properties
• => Example: Version tab of the
Prog1.exe Properties dialog
box
Setting Version Information
• The version resource fields
can be set using custom
attributes applied at the
assembly level in the source
code
using System.Reflection;
[assembly:AssemblyCompany("Trei Biti SRL")]
[assembly:AssemblyCopyright("Copyright (c) 2008 Programatorul Iscusit")]
[assembly:AssemblyProduct("Program exemplu curs PASSC")]
[assembly:AssemblyInformationalVersion("2.0.0.0")]
[assembly:AssemblyFileVersion("1.0.0.0")]
[assembly:AssemblyVersion("3.0.0.0")]
Deployment of Assemblies
• Two kinds of assemblies:
– Privately deployed assemblies:
• Are used by a single application
• Reside in the application directory (or in a place explicitly configured
in the application)
• Can be simply installed (copied) and uninstalled
– Shared assemblies:
• Are accessible to multiple applications
• Located at c:\winnt\assembly
• Add assemblies by
– Installer program
– gacutil.exe
• Shared Assemblies must have a “strong name”:
– Guarantees name uniqueness (two different producers could write a
library with the same name)
– Protect version lineage
» No one else can create a new version of your assembly
– a strongly named assembly is signed with a publisher’s public/private
key pair that uniquely identifies the assembly’s publisher.
Conclusion on Assemblies
• An assembly is a unit of reuse, versioning, and security.
• It allows you to partition your types and resources into separate files
so that you and consumers of your assembly get to determine which
files to package together and deploy.
• Once the CLR loads the file containing the manifest, it can
determine which of the assembly’s other files contain the types and
resources that the application is referencing.
• Assemblies are self-describing: Anyone consuming the assembly
is required to know only the name of the file containing the
manifest; the file partitioning is then abstracted away from the
consumer and may change in the future without breaking the
application’s behavior.
• An application consists of one or more assemblies: this assures the
needed technical infrastructure (metadata, MSIL) for language
interoperability
– Example:
– MyClassInCsharp
– MyProgramInJsharp
Example:
J# program uses C# class
// compile with
// csc /t:library MyClassInCsharp.cs
// produces MyClassInCsharp.dll
C#
//compile with
// vjc /r:MyClassInCsharp.dll
MyProgramInJsharp.jsl
J#
Import System.*;
using System;
public class MyClassInCsharp {
public void doSomething(int x) {
Console.WriteLine("doSomething on {0}", x);
}
}
public class MyClassInJsharp extends
MyClassInCsharp {
public void doSomethingSpecial() {
doSomething(999);
}
}
public class MyProgramInJsharp {
public static void main(String[] args) {
MyClassInCsharp c=new MyClassInCsharp();
c.doSomething(5);
MyClassInJsharp j=new MyClassInJsharp();
j.doSomethingSpecial();
}
}
Interoperability
Cross Language
•
Common Type System (CTS)
–
•
Common Language Specification (CLS)
–
•
Defines what language features are supported by the CLR:
superset of the data types used by most modern programming
languages
Defines what language features are essential to be implemented
by languages that want to produce code guaranteed to
interoperate with other languages. A subset of CTS that allows
code written in different languages to interoperate.
What languages?
–
–
Microsoft: C#, C++, Visual Basic, J#, JScript
Third-Party: Cobol, Eiffel, Smalltalk, Scheme, Oberon, Haskell,
Python, Perl, …
[Richter] – fig.1.6
Common Type System
•
•
CTS is a formal specification that describes how types are defined and how
they behave.
CTS establishes several rules regarding following issues:
–
–
–
–
–
•
•
•
What kind of members can a type contain
Type visibility and access to the members of a type.
Type inheritance, virtual functions
Object lifetime
All types must (ultimately) inherit from a predefined type: System.Object. This
Object is the root of all other types and therefore guarantees every type instance
has a minimum set of behaviors.
These rules have been designed to accommodate the semantics
expressible in modern-day programming languages.
In fact, developers don’t need to learn the CTS rules per se since the
language they choose will expose its own language syntax and type rules
and will map the language-specific syntax into the “language” of the CLR
when it emits the managed module.
CTS rules are more important for language and compiler developers
CTS: Type members
• The CTS specification states that a type can contain zero or more
members, that can be:
– Field A data variable that is part of the object’s state. Fields are
identified by their name and type.
– Method A function that performs an operation on the object, often
changing the object’s state. Methods have a name, a signature, and
modifiers. The signature specifies the calling convention, the number of
parameters (and their sequence), the types of the parameters, and the
type of value returned by the method.
– Property To the caller, this member looks like a field. But to the type
implementer, looks like a method (or two). Properties allow an
implementer to validate input parameters and object state before
accessing the value and/or calculate a value only when necessary. They
also allow a user of the type to have simplified syntax. Finally,
properties allow you to create read-only or write-only “fields.”
– Event An event allows a notification mechanism between an object and
other interested objects. For example, a button could offer an event that
notifies other objects when the button is clicked
CTS: Type visibility and access to
members
•
•
•
The CTS also specifies the rules for type visibility and for access to the
members of a type.
The CTS establishes the rules by which assemblies form a boundary of
visibility for a type, and the CLR enforces the visibility rules.
The valid options for controlling access to a method or a field:
– Private The method is callable only by other methods in the same class type.
– Family The method is callable by derived types, regardless of whether they are
within the same assembly. Note that many languages (such as C++ and C#)
refer to family as protected.
– Family and assembly The method is callable by derived types, but only if the
derived type is defined in the same assembly. Many languages (such as C# and
Visual Basic) don’t offer this access control. Of course, IL Assembly language
makes it available.
– Assembly The method is callable by any code in the same assembly. Many
languages refer to assembly as internal.
– Family or assembly The method is callable by derived types in any assembly.
The method is also callable by any types in the same assembly. C# refers to
family or assembly as protected internal.
– Public The method is callable by any code in any assembly.
CTS: System.Object
• Here’s another CTS rule: All types must ultimately inherit
from a predefined type: System.Object.
• System.Object is the root of all other types and
therefore guarantees every type instance has a minimum
set of behaviors.
• Specifically, the System.Object type allows you to do
the following:
–
–
–
–
–
Compare two instances for equality
Obtain a hash code for the instance
Query the true type of an instance
Perform a shallow (bitwise) copy of the instance
Obtain a string representation of the instance’s object’s current
state
Common Language Specification
• CLS is a subset of CTS
• A component that uses only CLS features in the API that it
exposes to other code (including derived classes) is
guaranteed to be accessible from any programming language
that supports the CLS.
• Components that adhere to the CLS rules and use only the
features included in the CLS are said to be CLS-compliant
components.
• Why do we need CLS, besides CTS ?
– CTS is too large to be integrally supported by all languages: the
CLS was designed to be large enough to include the language
constructs that are commonly needed by developers, yet small
enough that most languages are able to support it.
– In addition, any language construct that makes it impossible to
rapidly verify the type safety of code was excluded from the CLS
so that all CLS-compliant languages can produce verifiable code if
they choose to do so.
Some of the CLS Rules
• CLS rules apply only to those parts of a type that are exposed
outside the defining assembly.
• For two identifiers to be considered distinct, they must differ by more
than just their case.
• The .NET Framework class library includes types that correspond to
the primitive data types that compilers use. Of these types, the
following are CLS-compliant: Byte, Int16, Int32, Int64, Single,
Double, Boolean, Char, Decimal, IntPtr, and String.
• Methods are allowed to be overloaded only based on the number
and types of their parameters. Operator overloading is not in the
CLS.
• The only calling convention supported by the CLS is the standard
managed calling convention; variable length argument lists are not
allowed
CLSCompliant Attribute
• Assemblies explicitly indicate CLS compliance with
CLSCompliantAttribute.
• [assembly:CLSCompliant(true)]
• This setting will generate warnings at compilation if the
assembly contains non-CLS-compliant code
Example:
J# program uses C# class
// compile with
// csc /t:library MyClassInCsharp.cs
// produces MyClassInCsharp.dll
C#
//compile with
// vjc /r:MyClassInCsharp.dll
MyProgramInJsharp.jsl
J#
[assembly: CLSCompliant(true)];
Import System.*;
using System;
public class MyClassInCsharp {
public void doSomething(int x) {
Console.WriteLine("doSomething on {0}", x);
}
}
A module that will be
consumed in another language
must be CLSCompliant.
The consumer module doesn’t
has to be CLSCompliant.
public class MyClassInJsharp extends
MyClassInCsharp {
public void doSomethingSpecial() {
doSomething(999);
}
}
public class MyProgramInJsharp {
public static void main(String[] args) {
MyClassInCsharp c=new MyClassInCsharp();
c.doSomething(5);
MyClassInJsharp j=new MyClassInJsharp();
j.doSomethingSpecial();
}
}
Example:
J# program uses C# class
// compile with
// csc /t:library MyClassInCsharp.cs
// produces MyClassInCsharp.dll
//compile with
// vjc /r:MyClassInCsharp.dll MyProgramInJsharp.jsl
C#
[assembly: CLSCompliant(true)];
using System;
public class MyClassInCsharp {
public void doSomething(int x) {
Console.WriteLine("doSomething on {0}", x);
}
}
J#
Import System.*;
public class MyClassInJsharp extends
MyClassInCsharp {
public void doSomethingSpecial() {
doSomething(999);
}
public void dosomethingspecial() {
doSomething(111);
}
}
Type MyClassInJsharp is now NonCLSCompliant because it has 2
members with the same name and
signature (name case doesen’t matter).
Adding Non-CLSCompliant code
to the consumer module is OK !
MyProgramInJsharp works
public class MyProgramInJsharp {
public static void main(String[] args) {
MyClassInCsharp c=new MyClassInCsharp();
c.doSomething(5);
MyClassInJsharp j=new MyClassInJsharp();
j.doSomethingSpecial();
}
}
Example:
Defining a CLS-Compliant class in C++
// compile with
// cl /CLR:safe /LD MyClassInCpp.cpp
// produces MyClassInCpp.dll
C++
using namespace System;
[assembly: CLSCompliant(true)];
public ref class MyClassInCpp {
public:
void doSomething (int x);
};
void MyClassInCpp::doSomething (int x) {
Console::WriteLine("CPP: do Something on
{0}", x);
}
The Visual C
compiler can
generate managed
or native code
(default)
A CLSCompliant
module in C++
A managed class
(C++ can support both
managed and
unmanaged types)
Example:
J# program uses C# and C++ classes
MyClassInCpp.dll
C++
//compile with
// vjc /r:MyClassInCsharp.dll
//
/r:MyClassInCpp.dll
//
MyProgramInJsharp.jsl
J#
Import System.*;
MyClassInCsharp.dll
C#
public class MyClassInJsharp extends MyClassInCsharp {
public void doSomethingSpecial() {
doSomething(999);
}
}
public class MyProgramInJsharp {
public static void main(String[] args) {
MyClassInCsharp c=new MyClassInCsharp();
c.doSomething(5);
MyClassInJsharp j=new MyClassInJsharp();
j.doSomethingSpecial();
MyClassInCpp cpp=new MyClassInCpp();
cpp.doSomething(77);
}
}
Example:
C++ program uses C# and C++ classes
MyClassInCpp.dll
C++
// compile with
// cl /CLR MyProgramInCpp.cpp
#using <MyClassInCpp.dll>
#using <MyClassInCsharp.dll>
MyClassInCsharp.dll
C#
public ref class MySpecial:MyClassInCsharp {
public: void doSpecial();
};
void MySpecial::doSpecial() {
doSomething(777);
}
void main(void) {
MyClassInCpp cpp;
cpp.doSomething(56);
MyClassInCsharp c;
c.doSomething(99);
MySpecial s;
s.doSpecial();
}
C++
.NET Generics across languages
• Generics authored in one .NET language may be used in other .NET
languages.
• Only some languages on the .NET Framework platform provide
support for authoring generic types and methods.
• J# does not support authoring of generic collection classes, but it
does extend the Java-language syntax to provide support for using
specializations of generic types and methods defined in other .NET
Framework languages.
• Example: a generic is defined in C# and consumed in J#.
– The C# code defines a type parameter T which is unknown in the
compiled assembly. The J# code supplies a type argument to the
generic, thus generating a constructor where all unknown type
parameters have been replaced by actual types.
[MSDN Library: Generics in J#]
Example:
J# program consumes C# Generic Class
C#
// compile with
// csc /t:library MyGeneric.cs
// produces MyGeneric.dll
public class MyGeneric<T>
{
public T Field;
}
J#
//compile with
// vjc /r:MyGeneric.dll GenericConsumer.jsl
public class MyClass {
public int x;
}
public class app
{
public static void main(String [] args)
{
MyGeneric<int> g1 =
new MyGeneric<int>();
MyGeneric<MyClass> g2 =
new MyGeneric<MyClass>();
}
}
Interoperability
Managed/Unmanaged
• .NET provides interoperability mechanism
to permit managed code to call into
unmanaged code and vice versa
• Why?
– Existing code works, why rewrite it?
– Calling Microsoft functionality not yet available
as .NET assemblies
– Calling 3rd party native code
– Migrate your code incrementally
Interoperability
Managed/Unmanaged
• Three complementary technologies enable these
managed/unmanaged interactions:
– Platform Invoke (sometimes referred to as P/Invoke) enables
calling any function in any unmanaged language as long as its
signature is redeclared in managed source code.
– COM interop enables calling into COM components in any
managed language in a manner similar to using normal
managed components, and vice versa. COM interop is
comprised of core services provided by the CLR, plus some
tools and APIs in the System.Runtime.InteropServices
namespace.
– C++ interop (sometimes referred to as It Just Works (IJW)) is a
C++-specific feature, which enables flat APIs to be used directly,
as they have always been used.
[MSDN Library: An Overview of Managed/Unmanaged Code Interoperability ]
Platform Invoke
•
When platform invoke calls an unmanaged function, it performs the
following sequence of actions:
– Locates the DLL containing the function.
– Loads the DLL into memory.
– Locates the address of the function in memory and pushes its arguments onto
the stack, marshaling data as required.
– Transfers control to the unmanaged function.
[MSDN Library]
Calling a DLL Export Directly from C#
• To declare a method as having an implementation from a DLL
export, do the following:
– Declare the method with the static and extern C# keywords.
– Attach the DllImport attribute to the method. The DllImport attribute
allows you to specify the name of the DLL that contains the method.
The common practice is to name the C# method the same as the
exported method, but you can also use a different name for the C#
method, specifying the EntryPoint.
using System;
using System.Runtime.InteropServices;
class PlatformInvokeTest {
[DllImport("msvcrt.dll")]
public static extern int puts(string c);
public static void Main() {
puts("Test");
}
}
[MSDN Library: Platform Invoke Tutorial ]
Default Marshaling and Specifying Custom Marshaling
for Parameters to Unmanaged Methods
• When calling an unmanaged function from C# code, the common
language runtime must marshal the parameters and return values.
• For every .NET Framework type there is a default unmanaged type,
which the common language runtime will use to marshal data across
a managed to unmanaged function call.
• For example, the default marshaling for C# string values is to the
type LPTSTR (pointer to TCHAR char buffer). You can override the
default marshaling using the MarshalAs attribute in the C#
declaration of the unmanaged function.
[DllImport("msvcrt.dll")]
public static extern int puts(
[MarshalAs(UnmanagedType.LPStr)] string m);
C++ Interop
• The Visual C++ compiler (cl) can generate IL code or
native code
• Using compile switch /CLR it generates IL code from old
C++ source files
• Although the IL code produced is managed, the data is
not: data objects that are not explicitly defined as
managed types have no metadata associated, are not
allocated from the managed heap and are not garbage
collected.
• A C++ program can use both managed and unmanaged
types (IJW - It Just Works)
– Example: A program that calls the standard C library function
printf (unmanaged code) and the System.Console.WriteLine
method (managed code).
C++ Interop Example
// compile with cl /CLR CppInterop.cpp
#include <stdio.h> // For printf
using namespace System; // For System namespace types
// Implement a normal C/C++ main function
void main() {
// Call the C runtime library’s printf function.
printf("Displayed by printf.\r\n");
// Call the FCL’s System.Console’s WriteLine method.
Console::WriteLine("Displayed by Console::WriteLine.");
}
Download