<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4497717523385991248</id><updated>2011-10-10T19:24:29.681-07:00</updated><category term='c#'/><category term='synchronization'/><category term='C# LINQ SQL ENTITY DATABASE UPDATE'/><category term='multithreading'/><category term='strings'/><category term='SQL'/><category term='LINQ SQL Transaction Deathlock C# recovery'/><category term='C# COM Interop Extension Method Wrap'/><title type='text'>Christophe Keller's Blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://christophekeller.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4497717523385991248/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://christophekeller.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Christophe Keller</name><uri>http://www.blogger.com/profile/05628192032865633638</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_HEcFPYm-zKk/SxjqUI016nI/AAAAAAAAAZ0/naMlVqq7Kzc/s1600-R/chris.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>6</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4497717523385991248.post-6566185816530596518</id><published>2011-01-11T02:24:00.000-08:00</published><updated>2011-01-11T03:44:59.886-08:00</updated><title type='text'>Why Adaptative Menus Don't Work (and the Ribbon UI neither)</title><content type='html'>&lt;span style="font-size:180%;"&gt;Menu Wars&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A while back, Microsoft decided that adaptive menus, which adapt to only show the features users use the most, were a good idea. This feature debuted with Office 2003 and Windows XP.&lt;br /&gt;&lt;br /&gt;I think I can confidently say that most users hated them, and I was one of them. Why is that?&lt;br /&gt;&lt;br /&gt;The problem with adaptive menus is that the UI decides which menu entries to display using its own unfathomable intelligence. This surprises the user, which is a big no no in Software Design. Furthermore, the user has to learn how to display the hidden menu entries.&lt;br /&gt;&lt;br /&gt;But the biggest flaw adaptive menus have is that they shortcut spatial memory. For example, when I need to insert a picture into my favorite (or not so favorite) text editor, I think about about where spatially the menu is located in the menu structure and point to that area. Then around that space I try to find the entry with the matching words &lt;span style="font-style: italic;"&gt;Insert Picture&lt;/span&gt;. Adaptive menus don't give a damn about this way of proceeding.&lt;br /&gt;&lt;br /&gt;Thankfully Microsoft finally gave in and turned off adaptive menus by default in later versions of their Office programs.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;The Empire Strikes Back&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Not wanting to accept defeat, Microsoft stroke back with another monstrosity: the Ribbon UI.&lt;br /&gt;&lt;br /&gt;The Ribbon UI happily consumes screen real estate for no other apparent reason than to annoy the user. It shamelessly throws the previous spatial setup and order of menu features in disarray. The first time I started Word 2007 I think I searched for half an hour where the file menu had gone. Ha! Long-time users? We don't give a damn about long-time users...&lt;br /&gt;&lt;br /&gt;But the biggest problem with the Ribbon UI is that it suffers from the same problem as the adaptive menus: again it doesn't care about spatial memory. Several features are located in the same space of the rectangular area delimited by the ribbon UI. To find a feature, you need to do a kind of modal switch between the tab pages of the Ribbon UI, and you need to remember which tab page containing the feature you are interested in is associated with which tab caption.&lt;br /&gt;&lt;br /&gt;If this sounds complicated, well compared with the simplicity of good old menus it certainly is.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Return of The Jedi?&lt;/span&gt;&lt;br /&gt;One can only hope that in its future incarnation of software products, Microsoft will either completely diss personalized menus or the Ribbon UI (very unlikely), or at least give the user the option to choose which UI he wants to use. Only time will tell...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4497717523385991248-6566185816530596518?l=christophekeller.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christophekeller.blogspot.com/feeds/6566185816530596518/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://christophekeller.blogspot.com/2011/01/why-adaptative-menus-dont-work-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4497717523385991248/posts/default/6566185816530596518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4497717523385991248/posts/default/6566185816530596518'/><link rel='alternate' type='text/html' href='http://christophekeller.blogspot.com/2011/01/why-adaptative-menus-dont-work-and.html' title='Why Adaptative Menus Don&apos;t Work (and the Ribbon UI neither)'/><author><name>Christophe Keller</name><uri>http://www.blogger.com/profile/05628192032865633638</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_HEcFPYm-zKk/SxjqUI016nI/AAAAAAAAAZ0/naMlVqq7Kzc/s1600-R/chris.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4497717523385991248.post-1484266886543931080</id><published>2010-03-10T02:02:00.000-08:00</published><updated>2010-03-10T02:27:34.441-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C# COM Interop Extension Method Wrap'/><title type='text'>C# : How to Wrap Word InterOp COM Methods</title><content type='html'>If you ever used the Microsoft Office COM Interop classes to automate Word (or any other Office Application), you know that methods often take a lot of parameters, which can be a pain in the a..&lt;br /&gt;&lt;br /&gt;For example, the Word.Documents.Open() method takes 16! parameters in the Interop v 12 classes. You don't want to have to specify those at each method call.&lt;br /&gt;&lt;br /&gt;So what do you do? Well C# has a nice feature called extension methods since the version 3 of the .net Framework. You will leverage those to give you nice methods to call with few parameters. &lt;br /&gt;&lt;br /&gt;So you define a static class that will contain the extension methods on the various COM Interop classes you are interested in. For example, for the Open() method discussed above, see how I wrap it with my extension method:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;using Microsoft.Office.Interop.Word;&lt;br /&gt;&lt;br /&gt;namespace MyWordNamespace {&lt;br /&gt;&lt;br /&gt;    public static class ExtensionMethods {&lt;br /&gt;&lt;br /&gt;        public static Document Open(&lt;br /&gt;                this Documents documents, &lt;br /&gt;                string fileName) {&lt;br /&gt;&lt;br /&gt;            Object filename                 = fileName;&lt;br /&gt;            Object confirmConversions       = Type.Missing;&lt;br /&gt;            Object readOnly                 = Type.Missing;&lt;br /&gt;            Object addToRecentFiles         = Type.Missing;&lt;br /&gt;            Object passwordDocument         = Type.Missing;&lt;br /&gt;            Object passwordTemplate         = Type.Missing;&lt;br /&gt;            Object revert                   = Type.Missing;&lt;br /&gt;            Object writePasswordDocument    = Type.Missing;&lt;br /&gt;            Object writePasswordTemplate    = Type.Missing;&lt;br /&gt;            Object format                   = Type.Missing;&lt;br /&gt;            Object encoding                 = Type.Missing;&lt;br /&gt;            Object visible                  = Type.Missing;&lt;br /&gt;            Object openConflictDocument     = Type.Missing;&lt;br /&gt;            Object openAndRepair            = Type.Missing;&lt;br /&gt;            Object documentDirection        = Type.Missing;&lt;br /&gt;            Object noEncodingDialog         = Type.Missing;&lt;br /&gt;            Object xmlTransform             = Type.Missing;&lt;br /&gt;&lt;br /&gt;            return documents.Open(&lt;br /&gt;                ref filename,&lt;br /&gt;                ref confirmConversions,&lt;br /&gt;                ref readOnly,&lt;br /&gt;                ref addToRecentFiles,&lt;br /&gt;                ref passwordDocument,&lt;br /&gt;                ref passwordTemplate,&lt;br /&gt;                ref revert,&lt;br /&gt;                ref writePasswordDocument,&lt;br /&gt;                ref writePasswordTemplate,&lt;br /&gt;                ref format,&lt;br /&gt;                ref encoding,&lt;br /&gt;                ref visible,&lt;br /&gt;                ref openAndRepair,&lt;br /&gt;                ref documentDirection,&lt;br /&gt;                ref noEncodingDialog,&lt;br /&gt;                ref xmlTransform&lt;br /&gt;            );&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Which you can then call like this (I've also added wrappers for Documents.Close() and Application.Quit()):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;using Microsoft.Office.Interop.Word;&lt;br /&gt;using MyWordNamespace;&lt;br /&gt;&lt;br /&gt;namespace MyApplication {&lt;br /&gt;&lt;br /&gt;    class Program {&lt;br /&gt;&lt;br /&gt;        static void Main(string[] args) {&lt;br /&gt;&lt;br /&gt;            Application application = new Application();&lt;br /&gt;            try {&lt;br /&gt;                application.Visible = true;&lt;br /&gt;&lt;br /&gt;                Document document = application.Documents.Open(&lt;br /&gt;                    @"c:\temp\Document.docx"&lt;br /&gt;                );&lt;br /&gt;                Thread.Sleep(5000);&lt;br /&gt;&lt;br /&gt;                application.Documents.Close();&lt;br /&gt;            }&lt;br /&gt;            finally {                &lt;br /&gt;                application.Quit(WdSaveOptions.wdDoNotSaveChanges);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Nice, isn't it?&lt;br /&gt;&lt;br /&gt;Happy programming!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4497717523385991248-1484266886543931080?l=christophekeller.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christophekeller.blogspot.com/feeds/1484266886543931080/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://christophekeller.blogspot.com/2010/03/c-how-to-wrap-word-introp-com-methods.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4497717523385991248/posts/default/1484266886543931080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4497717523385991248/posts/default/1484266886543931080'/><link rel='alternate' type='text/html' href='http://christophekeller.blogspot.com/2010/03/c-how-to-wrap-word-introp-com-methods.html' title='C# : How to Wrap Word InterOp COM Methods'/><author><name>Christophe Keller</name><uri>http://www.blogger.com/profile/05628192032865633638</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_HEcFPYm-zKk/SxjqUI016nI/AAAAAAAAAZ0/naMlVqq7Kzc/s1600-R/chris.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4497717523385991248.post-6664324684556285695</id><published>2010-02-26T04:17:00.000-08:00</published><updated>2010-02-26T04:24:57.616-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='LINQ SQL Transaction Deathlock C# recovery'/><title type='text'>Linq To Sql: Handle a transaction deathlock</title><content type='html'>When using Linq To SQL, here's my pattern to retry an operation after it failed because a deathlock occured in the SQL Database:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;while (true) {&lt;br /&gt;    try {&lt;br /&gt;        using (var scope = new TransactionScope()) {&lt;br /&gt;            using (var db = new MyDataContext()) {&lt;br /&gt;&lt;br /&gt;                // Do what you need to do on the DB...&lt;br /&gt;&lt;br /&gt;                db.SubmitChanges();&lt;br /&gt;            }&lt;br /&gt;            scope.Complete();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        break;&lt;br /&gt;    }&lt;br /&gt;    catch (SqlException e) {&lt;br /&gt;        if (e.Number == 1205) {&lt;br /&gt;            Thread.Sleep(new Random.Next(1000));&lt;br /&gt;        }&lt;br /&gt;        else {&lt;br /&gt;            throw;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4497717523385991248-6664324684556285695?l=christophekeller.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christophekeller.blogspot.com/feeds/6664324684556285695/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://christophekeller.blogspot.com/2010/02/linq-to-sql-retrying-operation-after.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4497717523385991248/posts/default/6664324684556285695'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4497717523385991248/posts/default/6664324684556285695'/><link rel='alternate' type='text/html' href='http://christophekeller.blogspot.com/2010/02/linq-to-sql-retrying-operation-after.html' title='Linq To Sql: Handle a transaction deathlock'/><author><name>Christophe Keller</name><uri>http://www.blogger.com/profile/05628192032865633638</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_HEcFPYm-zKk/SxjqUI016nI/AAAAAAAAAZ0/naMlVqq7Kzc/s1600-R/chris.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4497717523385991248.post-317887321875404775</id><published>2010-02-11T23:36:00.000-08:00</published><updated>2010-02-12T00:04:30.853-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C# LINQ SQL ENTITY DATABASE UPDATE'/><title type='text'>C#: Linq To Sql: Updating a reattached entity</title><content type='html'>If you listen to Microsoft, you would believe than you can't reattach a changed entity to a new DataContext and submit the changed entity to the database. Rubbish! It can be done with a little bit of preparation.&lt;br /&gt;&lt;br /&gt;The first step is to make sure that the underlying table has a timestamp column. Then you need to make sure that the entity object takes this into account. The best is to only create the entity in Visual Studio's designer after the timestamp column has been added. If it already exists, delete it from the designer, then drop it from the Server Explorer to the designer again.&lt;br /&gt;&lt;br /&gt;Now that this basic infrastructure is in place, you only need to make sure that when you get an entity from a DataContext, and that entity will be updated and reattached to another DataContext later, the initial DataContext should have the EnableDeferredLoading set to false. You can then reattach to the second DataContext with the Attach&lt;T&gt;(T entity, bool isUpdated) method and submit the object. &lt;br /&gt;&lt;br /&gt;Example:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Product product;&lt;br /&gt;&lt;br /&gt;using (var db = new MyDataContext())&lt;br /&gt;    db.DeferredLoadingEnabled = false;&lt;br /&gt;    product = db.Products.SingleOrDefault(p =&gt; p.Id = "1");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;product.Name = "Updated Name";&lt;br /&gt;&lt;br /&gt;using (var db = new MyDataContext())&lt;br /&gt;    db.Attach(product, true);&lt;br /&gt;    db.SubmitChanges();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Voilà, you are done!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4497717523385991248-317887321875404775?l=christophekeller.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christophekeller.blogspot.com/feeds/317887321875404775/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://christophekeller.blogspot.com/2010/02/linq-to-sql-updating-reattached-entity.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4497717523385991248/posts/default/317887321875404775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4497717523385991248/posts/default/317887321875404775'/><link rel='alternate' type='text/html' href='http://christophekeller.blogspot.com/2010/02/linq-to-sql-updating-reattached-entity.html' title='C#: Linq To Sql: Updating a reattached entity'/><author><name>Christophe Keller</name><uri>http://www.blogger.com/profile/05628192032865633638</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_HEcFPYm-zKk/SxjqUI016nI/AAAAAAAAAZ0/naMlVqq7Kzc/s1600-R/chris.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4497717523385991248.post-1859297471333320359</id><published>2009-12-02T00:54:00.000-08:00</published><updated>2009-12-02T01:21:19.376-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='strings'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><title type='text'>C#: Use verbatim strings for SQL queries</title><content type='html'>Yes, I know, for some it might be rocket science, but you can use verbatim strings for SQL queries. In the following examples, which query is easier to read?&lt;br /&gt;&lt;br /&gt;This one?&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;string query = @"&lt;br /&gt;    SELECT &lt;br /&gt;        User.FirstName, &lt;br /&gt;        User.LastName, &lt;br /&gt;        User.Age,&lt;br /&gt;        User.Gender, &lt;br /&gt;        User.HairColor, &lt;br /&gt;        Adress.Street, &lt;br /&gt;        Adresse.Zip,&lt;br /&gt;        Adress.City, &lt;br /&gt;        Adress.Country &lt;br /&gt;    FROM &lt;br /&gt;        User &lt;br /&gt;    INNER JOIN &lt;br /&gt;        Adress ON User.AdressId = Adress.Id &lt;br /&gt;    SORT BY &lt;br /&gt;        User.FirstName, &lt;br /&gt;        User.LastName&lt;br /&gt;    ";&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;or this one?&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;string query = "SELECT User.FirstName, User.LastName, User.Age, "&lt;br /&gt;    + "User.Gender, User.HairColor, Adress.Street, Adresse.Zip, "&lt;br /&gt;    + "Adress.City, Adress.Country FROM User INNER JOIN Adress ON "&lt;br /&gt;    + "User.AdressId = Adress.Id SORT BY User.FirstName, "&lt;br /&gt;    + "User.LastName";&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The SQL engine doesn't care for the whitespace you introduce in the queries with the verbatim strings. So do your fellow programmers a favor and use them for your SQL queries!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4497717523385991248-1859297471333320359?l=christophekeller.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christophekeller.blogspot.com/feeds/1859297471333320359/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://christophekeller.blogspot.com/2009/12/c-use-verbatim-strings-for-sql-queries.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4497717523385991248/posts/default/1859297471333320359'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4497717523385991248/posts/default/1859297471333320359'/><link rel='alternate' type='text/html' href='http://christophekeller.blogspot.com/2009/12/c-use-verbatim-strings-for-sql-queries.html' title='C#: Use verbatim strings for SQL queries'/><author><name>Christophe Keller</name><uri>http://www.blogger.com/profile/05628192032865633638</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_HEcFPYm-zKk/SxjqUI016nI/AAAAAAAAAZ0/naMlVqq7Kzc/s1600-R/chris.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4497717523385991248.post-4242211071885191396</id><published>2009-12-01T02:38:00.001-08:00</published><updated>2009-12-01T03:55:38.980-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='synchronization'/><category scheme='http://www.blogger.com/atom/ns#' term='multithreading'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>C#: Multithreading IS simple</title><content type='html'>&lt;p&gt;OK, this attention-grabbing title is a little bit fueled by my frustration of having seen badly written multi-threading code once too often.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Multi-threading code has a reputation of being difficult to read and to write, and it's true that there are a lot of things to consider once you go down that route. However, I would also say that a large amount of the errors one sees in multi-threading code is due to the fact that no synchronization is used at all.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;So, the basic multi-threading principle is surprisingly simple: &lt;b&gt;If two (or more) threads access the same piece of data, you MUST synchronize access to it.&lt;/b&gt; This is true even if your PC has only one processor, as current processors are often multi-core.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;In C#, if several threads access some simple (value type) data, one typically uses the lock() statement, like the example below, where access to the Count property is thread-safe:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class MultiAccess {&lt;br /&gt;    private readonly object syncObject = new object();&lt;br /&gt;    private int count = 0&lt;br /&gt;&lt;br /&gt;    public int Count {&lt;br /&gt;        get {&lt;br /&gt;            lock (syncObject) {&lt;br /&gt;                return count;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        set {&lt;br /&gt;            lock (syncObject) {&lt;br /&gt;                count = value;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;syncObject is an object used solely for the purpose of synchronization, making it readonly ensures that it's reference can never be changed by malicious code. Obviously, there is more to multi-threading than that, but the above will nicely take care of the basics.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;That's it, happy programming&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4497717523385991248-4242211071885191396?l=christophekeller.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://christophekeller.blogspot.com/feeds/4242211071885191396/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://christophekeller.blogspot.com/2009/12/multithreading-is-simple.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4497717523385991248/posts/default/4242211071885191396'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4497717523385991248/posts/default/4242211071885191396'/><link rel='alternate' type='text/html' href='http://christophekeller.blogspot.com/2009/12/multithreading-is-simple.html' title='C#: Multithreading IS simple'/><author><name>Christophe Keller</name><uri>http://www.blogger.com/profile/05628192032865633638</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_HEcFPYm-zKk/SxjqUI016nI/AAAAAAAAAZ0/naMlVqq7Kzc/s1600-R/chris.jpg'/></author><thr:total>0</thr:total></entry></feed>
