Advanced C#Advanced C#Eric GunnersonEric Gunnerson
Program ManagerProgram ManagerVisual C# .NETVisual C# .NET
Microsoft CorporationMicrosoft Corporation
Advanced C# TopicsAdvanced C# Topics Visual Studio “Everett” FeaturesVisual Studio “Everett” Features Designing a New TypeDesigning a New Type Object DestructionObject Destruction Exception HandlingException Handling Unsafe CodeUnsafe Code
Visual Studio “Everett” FeaturesVisual Studio “Everett” Features Designing a New TypeDesigning a New Type Object DestructionObject Destruction Exception HandlingException Handling Unsafe CodeUnsafe Code
Advanced C# TopicsAdvanced C# Topics
Everett DemoEverett Demo
Designing a New TypeDesigning a New Type
C# has both C# has both reference and reference and value typesvalue types
Which is the right Which is the right one to use?one to use?
What are they?What are they?
Reference types:Reference types: Heap allocatedHeap allocated Tracked by the GCTracked by the GC Support inheritance, polymorphism, etc.Support inheritance, polymorphism, etc.
Value types:Value types: Stack or inline allocatedStack or inline allocated Not tracked by the GCNot tracked by the GC No inheritance, limited polymorphismNo inheritance, limited polymorphism
Other LanguagesOther Languages
Smalltalk only supports reference typesSmalltalk only supports reference types Simple, consistent modelSimple, consistent model DisadvantagesDisadvantages
““int j = 5;” does a heap allocationint j = 5;” does a heap allocation 100 ints in an array is 100 allocations100 ints in an array is 100 allocations Doesn’t interop well with existing primitive typesDoesn’t interop well with existing primitive types
Value TypesValue Types Advantages:Advantages:
Allocation is very fastAllocation is very fast Arrays involve a single allocationArrays involve a single allocation Reduced memory pressureReduced memory pressure
Less work for the GCLess work for the GC
Disadvantages:Disadvantages: No inheritanceNo inheritance Only polymorphic when boxedOnly polymorphic when boxed Boxing involves overheadBoxing involves overhead
Reference TypesReference Types
The basic type in .netThe basic type in .net Advantages:Advantages:
All object-oriented goodiesAll object-oriented goodies polymorphism, etc.polymorphism, etc.
Good performanceGood performance
Disadvantages:Disadvantages: Always requires heap allocationAlways requires heap allocation
GuidelinesGuidelines Use value types for:Use value types for:
Building a new data type (ie Complex)Building a new data type (ie Complex) LotsLots of small objects of small objects
Only really useful if they’re in an arrayOnly really useful if they’re in an array If not, boxing often means this isn’t worth itIf not, boxing often means this isn’t worth it
Size of typeSize of type Framework guidelines say <= 16 bytesFramework guidelines say <= 16 bytes Depends on usage of the typeDepends on usage of the type Benchmark to validate for your appBenchmark to validate for your app
If you hit limitations, you’re using it If you hit limitations, you’re using it wrongwrong
Visual Studio “Everett” FeaturesVisual Studio “Everett” Features Designing a New TypeDesigning a New Type Object DestructionObject Destruction Exception HandlingException Handling Ref and foreachRef and foreach Unsafe CodeUnsafe Code
Advanced C# TopicsAdvanced C# Topics
Object Object DestructionDestruction
Goal: Be able to control exactly Goal: Be able to control exactly when objects are destroyedwhen objects are destroyed
You want itYou want it You can’t have itYou can’t have it
A very complicated discussionA very complicated discussion See See http://www.gotdotnet.com/team/csharp/informationhttp://www.gotdotnet.com/team/csharp/information
Look for article on Resource managementLook for article on Resource management
Object DestructionObject Destruction
Garbage collection means you aren’t in Garbage collection means you aren’t in controlcontrol
GC chooses:GC chooses: When objects are destroyedWhen objects are destroyed Order of destructionOrder of destruction
Garbage collector can’t clean up Garbage collector can’t clean up unmanaged objectsunmanaged objects
How Bad is It?How Bad is It?
Mostly an issue for wrapper objectsMostly an issue for wrapper objects Database handlesDatabase handles FilesFiles GDI objects (fonts, pens, etc.)GDI objects (fonts, pens, etc.) Any object the GC doesn’t trackAny object the GC doesn’t track
All objects get cleaned upAll objects get cleaned up Some may take a bit longerSome may take a bit longer
Wrapper objectsWrapper objects
Cleanup at GC timeCleanup at GC time Objects with unmanaged resources Objects with unmanaged resources
implement a finalizer to free those implement a finalizer to free those resourcesresources
Early CleanupEarly Cleanup Objects implement IDisposable, users call Objects implement IDisposable, users call
Dispose() to clean upDispose() to clean up
Scenario 1Scenario 1User Calls Dispose()User Calls Dispose()
Unmanaged Resource
Font object
Dispose()
Dispose()
freeIntPtr myResource;
Font font;
Dispose() means free my resources, and call Dispose() on any contained objects
Scenario 2Scenario 2Object Finalized by GCObject Finalized by GC
Unmanaged Resource
Font object
Finalize()
Dispose()?
freeIntPtr myResource;
Font font;
Finalize() means free my resources only; other managed resources will also get finalized
X
Finalize()
Implementing Implementing IDisposableIDisposable
Design pattern for early cleanupDesign pattern for early cleanup Only required when you:Only required when you:
Wrap unmanaged resourcesWrap unmanaged resources You’ll need a destructor tooYou’ll need a destructor too
oror Need to be able to clean up earlyNeed to be able to clean up early
DestructorsDestructors
Object.Finalize is not accessible in Object.Finalize is not accessible in C#C#public class Resource: IDisposablepublic class Resource: IDisposable
{{ ~Resource() {...}~Resource() {...}}}
public class Resource: IDisposablepublic class Resource: IDisposable{{ protected override void Finalize() {protected override void Finalize() { try {try { ...... }} finally {finally { base.Finalize();base.Finalize(); }} }}}}
Doing the Doing the ImplementationImplementation
public class Resource: IDisposablepublic class Resource: IDisposable{{ IntPtr myResource;IntPtr myResource; Font font;Font font;
protected virtual void Dispose(bool disposing) {protected virtual void Dispose(bool disposing) { if (disposing) {if (disposing) { font.Dispose();font.Dispose(); GC.SuppressFinalize(this);GC.SuppressFinalize(this); }} FreeThatResource(myResource);FreeThatResource(myResource); }} public void Dispose() {public void Dispose() { Dispose(true);Dispose(true); }} ~Resource() {~Resource() { Dispose(false);Dispose(false); }}}}
Visual Studio “Everett” FeaturesVisual Studio “Everett” Features Designing a New TypeDesigning a New Type Object DestructionObject Destruction Exception HandlingException Handling Unsafe CodeUnsafe Code
Advanced C# TopicsAdvanced C# Topics
Exception HandlingException Handling
Provides tremendous benefitsProvides tremendous benefits
Requires a different way of thinkingRequires a different way of thinking
The old wayThe old way
RETVAL Process(int a, int x, int y, int z)RETVAL Process(int a, int x, int y, int z){{RETVAL retval;RETVAL retval;if ((retval = function(x, y, z)) != OK)if ((retval = function(x, y, z)) != OK)
return retval;return retval;
if ((retval = function2(a, y)) != OK)if ((retval = function2(a, y)) != OK)return retval;return retval;
}}
Option 1Option 1void Process(int a, int x, int y, int z)void Process(int a, int x, int y, int z){{ trytry {{
function(x, y, z);function(x, y, z);}}catch (Exception e)catch (Exception e){{
throw e;throw e;}}
trytry {{
function2(a, y);function2(a, y);}}catch (Exception e)catch (Exception e){{
throw e;throw e;}}
}}
Option 2Option 2
void Process(int a, int x, int y, int z)void Process(int a, int x, int y, int z){{ trytry {{
function(x, y, z);function(x, y, z);function2(a, y);function2(a, y);
}}catch (Exception e)catch (Exception e){{
throw e;throw e;}}
}}
Option 3Option 3void Process(int a, int x, int y, int z)void Process(int a, int x, int y, int z){{
function(x, y, z);function(x, y, z);function2(a, y);function2(a, y);
}}
Exception HandlingException Handling
You get correct behavior by defaultYou get correct behavior by default Only catch an exception when you can Only catch an exception when you can
do something useful for the userdo something useful for the user You can write lots of unnecessary code, You can write lots of unnecessary code,
but at least your code will be less robustbut at least your code will be less robust
When to catchWhen to catch
Something specific happens, and we can Something specific happens, and we can helphelp
trytry{{ StreamReader s = File.OpenText(filename);StreamReader s = File.OpenText(filename);}}
catch (Exception e)catch (Exception e){{ Console.WriteLine(“Invalid filename: {0}”, filename);Console.WriteLine(“Invalid filename: {0}”, filename);}}
trytry{{ StreamReader s = File.OpenText(filename);StreamReader s = File.OpenText(filename);}}
catch (FileNotFoundException e)catch (FileNotFoundException e){{ Console.WriteLine(e);Console.WriteLine(e);}}
trytry{{ ExecuteBigProcess();ExecuteBigProcess();}}
catch (Exception e)catch (Exception e){{ log.WriteLine(e.ToString());log.WriteLine(e.ToString()); throw;throw;}}
trytry{{ ExecuteBigProcess();ExecuteBigProcess();}}
catch (Exception e)catch (Exception e){{ throw new throw new MyException(“Error executing BigProcess”, e); MyException(“Error executing BigProcess”, e);}}
When to catchWhen to catch
We need to log or wrap an exceptionWe need to log or wrap an exception
When to catchWhen to catch
We’d die otherwiseWe’d die otherwisepublic static void Main()public static void Main(){{ while (true)while (true) {{ trytry {{ MainLoop();MainLoop(); }} catch (Exception e)catch (Exception e) {{ Console.WriteLine(“Exception caught, trying to continue”);Console.WriteLine(“Exception caught, trying to continue”); Console.WriteLine(e);Console.WriteLine(e); }} }}}}
Finally statementFinally statement
If an exception is thrown andIf an exception is thrown and There’s something to clean upThere’s something to clean up
Close a fileClose a file Release a DB handleRelease a DB handle
Using statement makes this easierUsing statement makes this easier Works on anything that implements Works on anything that implements
IDisposableIDisposable
Using StatementUsing Statement Acquire, Execute, Release patternAcquire, Execute, Release pattern Works with any IDisposable objectWorks with any IDisposable object
Data access classes, streams, text readers Data access classes, streams, text readers and writers, network classes, etc.and writers, network classes, etc.
using (Resource res = new Resource()) {using (Resource res = new Resource()) { res.DoWork();res.DoWork();}}
Resource res = new Resource(...);Resource res = new Resource(...);try {try { res.DoWork();res.DoWork();}}finally {finally { if (res != null) ((IDisposable)res).Dispose();if (res != null) ((IDisposable)res).Dispose();}}
Using StatementUsing Statement
static void Copy(string sourceName, string destName) {static void Copy(string sourceName, string destName) { Stream input = File.OpenRead(sourceName);Stream input = File.OpenRead(sourceName); Stream output = File.Create(destName);Stream output = File.Create(destName); byte[] b = new byte[65536];byte[] b = new byte[65536]; int n;int n; while ((n = input.Read(b, 0, b.Length)) != 0) {while ((n = input.Read(b, 0, b.Length)) != 0) { output.Write(b, 0, n);output.Write(b, 0, n); }} output.Close();output.Close(); input.Close();input.Close();}}
static void Copy(string sourceName, string destName) {static void Copy(string sourceName, string destName) { Stream input = File.OpenRead(sourceName);Stream input = File.OpenRead(sourceName); try {try { Stream output = File.Create(destName);Stream output = File.Create(destName); try {try { byte[] b = new byte[65536];byte[] b = new byte[65536]; int n;int n; while ((n = input.Read(b, 0, b.Length)) != 0) {while ((n = input.Read(b, 0, b.Length)) != 0) { output.Write(b, 0, n);output.Write(b, 0, n); }} }} finally {finally { output.Close();output.Close(); }} }} finally {finally { input.Close();input.Close(); }}}}
static void Copy(string sourceName, string destName) {static void Copy(string sourceName, string destName) { using (Stream input = File.OpenRead(sourceName))using (Stream input = File.OpenRead(sourceName)) using (Stream output = File.Create(destName)) {using (Stream output = File.Create(destName)) { byte[] b = new byte[65536];byte[] b = new byte[65536]; int n;int n; while ((n = input.Read(b, 0, b.Length)) != 0) {while ((n = input.Read(b, 0, b.Length)) != 0) { output.Write(b, 0, n);output.Write(b, 0, n); }} }}}}
Exceptions vs Return Exceptions vs Return CodesCodes
Exceptions are meant for Exceptions are meant for exceptional casesexceptional cases Invalid parametersInvalid parameters Can’t perform operationCan’t perform operation
Should not occur during normal Should not occur during normal program operationprogram operation User interaction is a grey areaUser interaction is a grey area
Using Return ValuesUsing Return Values
Okay if your caller Okay if your caller alwaysalways will have to will have to check and recover from somethingcheck and recover from something Make sure you don’t force them to write:Make sure you don’t force them to write:
Shouldn’t be possible to do the wrong Shouldn’t be possible to do the wrong thingthing File.Open() returns null on file not foundFile.Open() returns null on file not found You can’t ignore thisYou can’t ignore this
bool success = TryOperation(param1, param2);bool success = TryOperation(param1, param2);if (!success)if (!success) return success;return success;
SummarySummary
Understand how the model worksUnderstand how the model works Don’t work too hardDon’t work too hard If you can’t do something useful, If you can’t do something useful,
don’t catchdon’t catch
Visual Studio “Everett” FeaturesVisual Studio “Everett” Features Designing a New TypeDesigning a New Type Object DestructionObject Destruction Exception HandlingException Handling Unsafe CodeUnsafe Code
Advanced C# TopicsAdvanced C# Topics
Unsafe CodeUnsafe Code When pointers are a necessityWhen pointers are a necessity
Advanced COM and P/Invoke interopAdvanced COM and P/Invoke interop Existing binary structuresExisting binary structures Performance extremesPerformance extremes
Low-level code without leaving the boxLow-level code without leaving the box Basically “inline C”Basically “inline C”
struct COFFHeader {struct COFFHeader { public ushort MachineType;public ushort MachineType; public ushort NumberOfSections;public ushort NumberOfSections; … … public ushort Characteristics;public ushort Characteristics;}}
private COFFHeader fileHeader;private COFFHeader fileHeader;
void ReadHeader(BinaryStream InFile)void ReadHeader(BinaryStream InFile){{ fileHeader.MachineType = inFile.ReadUInt16();fileHeader.MachineType = inFile.ReadUInt16(); fileHeader.NumberOfSections = inFile.ReadUInt16();fileHeader.NumberOfSections = inFile.ReadUInt16(); // …// … fileHeader.Characteristics = inFile.ReadUInt16();fileHeader.Characteristics = inFile.ReadUInt16();}}
private COFFHeader fileHeader;private COFFHeader fileHeader;
unsafe void ReadHeader(BinaryStream InFile)unsafe void ReadHeader(BinaryStream InFile){{ byte[] buffer = InFile.ReadBytes(sizeof(COFFHeader));byte[] buffer = InFile.ReadBytes(sizeof(COFFHeader)); fixed (byte* headerPtr = buffer) fixed (byte* headerPtr = buffer) {{ fileHeader = *((COFFHeader*)headerPtr);fileHeader = *((COFFHeader*)headerPtr); }}}}
Existing Binary Existing Binary Structures Structures
Image ProcessingImage Processing
demodemo
Additional ResourcesAdditional Resources
C# Community SitesC# Community Sites http://www.csharp.nethttp://www.csharp.net
See information page for my columnsSee information page for my columns Sign up for C# Community NewsletterSign up for C# Community Newsletter
C# newsgroupC# newsgroup microsoft.public.dotnet.languages.csharmicrosoft.public.dotnet.languages.cshar
pp
Thank YouThank You
Questions?Questions?
Top Related