Thursday, November 22, 2007 1:14 PM bart

C# 3.0 Object Initializers Revisited

A while ago I posted about this new C# 3.0 feature. Although the IL code (aargh, yet another of these posts :-)) in that post reveals how object initializers are implemented internally, I wanted to make it slightly more explicit over here to avoid confusion.

Consider the following C# 3.0 fragment:

using System;

class Oini
{
   public static void Main()
   {
      Customer c = new Customer() { Name = "Bart", City = "Redmond", Age = 24 };
   }
}

This is not equivalent to:

using System;

class Oini
{
   public static void Main()
   {
      Customer c = new Customer();
      c.Name = "Bart";
      c.City = "Redmond";
      c.Age = 24;
   }
}

It is equivalent to the following however:

using System;

class Oini
{
   public static void Main()
   {
      Customer __t = new Customer();
      __t.Name = "Bart";
      __t.City = "Redmond";
      __t.Age = 24;
      Customer c = __t;
   }
}

I know it's subtle but there's a very good reason to do it this way: atomic assignment. Assignments should be read from right to left:

Customer c = new Customer() { Name = "Bart", City = "Redmond", Age = 24 };

means

  1. evaluate the right-hand side (rhs):

    new Customer() { Name = "Bart", City = "Redmond", Age = 24 }
  2. assign it to the left-hand side (lhs):

    Customer c

therefore, we need a temporary object to evaluate the right-hand side first prior to assigning it to the target variable.

One place where this subtlety is quite important is the use of multi-threading. It's a bit of a convoluted sample, I agree, since in multi-threaded circumstances you'll likely have a locking-strategy or so in place to avoid base states but anyhow, here's a sample:

using System;
using System.Threading;

class Customer
{
   public string Name { get; set; }
   public string City { get; set; }
   public int Age { get; set; }
}

class Demo
{
   static Customer c;
   static int n = 0;
   static bool
safe = false;

   static void Main(string[] args)
   {
      safe = args.Length > 0;

      Init();

      AppDomain.CurrentDomain.UnhandledException +=
         delegate(object sender, UnhandledExceptionEventArgs e)
         {
            Console.WriteLine("Invalid state after " + n + " assignments.");
            Environment.Exit(1);
         };

      new Thread(() => Monitor()).Start();

      for (n = 1; ; n++)
         Init();
   }

   static void Init()
   {
      if (safe)
      {
         c = new Customer() {
            Name = "Bart",
            City = "Redmond",
            Age = 24
         };
      }
      else
      {
         c = new Customer();
         c.Name = "Bart";
         c.City = "Redmond";
         c.Age = 24;
      }
   }

   static void Monitor()
   {
      while (true)
      {

         if (c.Name != "Bart" || c.City != "Redmond" || c.Age != 24)
           
throw new Exception("Bad state detected");
      }
   }
}

If you execute this application without command-line arguments it should fail pretty quickly. However if you run it with some parameter, safe will be set to true, which causes Init to use the C# 3.0 implementation of object initialization, which is atomic. So we shouldn't get in intermediate states at all.

image

Here's the reverse translation of the Init body using Reflector:

image

If you understand this sample, you know why atomic assignment matters (and that's a good thing :-)). To pinpoint the core problem, consider the following fragment of Init (in the safe-negative case):

         c = new Customer();
         c.Name = "Bart";
         c.City = "Redmond";
         c.Age = 24;

If the monitoring thread gets a chance to kick in somewhere in the middle of executing these four statements, the state is "corrupted". Obviously you can fix this by putting a lock in place (small exercise) but it's nice to know the atomic character of object initializers in C# 3.0 anyhow.

Enjoy!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Filed under:

Comments

# re: C# 3.0 Object Initializers Revisited

Friday, November 23, 2007 9:49 AM by bastian

So, the point of this initializers is to circumvent the lack of a proper constructor, right?

# re: C# 3.0 Object Initializers Revisited

Friday, November 23, 2007 12:23 PM by bart

Hi Bastian,

That's right. In general words: atomic initialization without a proper constructor overload. In "regular" coding places this is mostly a convenience feature, albeit a very useful one (with nice semantics as outlined in this post). However, when expression trees enter the picture (e.g. implicitly present in LINQ to SQL etc) the story changes a little. Consider the following fragment:

using System;

using System.Linq.Expressions;

class Init

{

  static void Main()

  {

     Func<Customer> f1 = () => new Customer() { Name = "Bart", Age = 24, City = "Redmond" };

     Func<Customer> f2 = () => {

        Customer c = new Customer();

        c.Name = "Bart";

        c.Age = 24;

        c.City = "Redmond";

        return c;

     };

     Expression<Func<Customer>> e1 = () => new Customer() { Name = "Bart", Age = 24, City = "Redmond" };

     Expression<Func<Customer>> e2 = () => {

        Customer c = new Customer();

        c.Name = "Bart";

        c.Age = 24;

        c.City = "Redmond";

        return c;

     };

  }

}

class Customer

{

  public string Name { get; set; }

  public string City { get; set; }

  public int Age { get; set; }

}

The lambdas in f1 and f2 will compile fine; after all these are just syntactical sugar on top of anonymous methods:

     Func<Customer> f1 = delegate { return new Customer() { Name = "Bart", Age = 24, City = "Redmond" }; };

     Func<Customer> f2 = delegate {

        Customer c = new Customer();

        c.Name = "Bart";

        c.Age = 24;

        c.City = "Redmond";

        return c;

     };

Expression e1 is fine too, since the rhs of the assignment (the lambda () => new Customer() { Name = "Bart", Age = 24, City = "Redmond" }) can be translated into an expression tree, more specifically a NewExpression with a set of MemberBinding elements in it.

Expression e2 won't compile however, since the body of the lambda isn't an expression but a statement block. Expression trees can't express this so the idea would fall apart in case we didn't have object initializer syntax.

I'll blog more about expression trees if time permits.

Cheers,

-Bart

# Development in a Blink &raquo; Blog Archive &raquo; The atomic character of object initializers in C# 3.0

Pingback from  Development in a Blink  &raquo; Blog Archive   &raquo; The atomic character of object initializers in C# 3.0

# C# 3.0 New Feature for the Week #2: Object and Collection Initializers

Wednesday, November 28, 2007 12:38 PM by Doron's .NET Space

Last week I started my series of posts about new C# 3.0 features, and my second post will be about object

# DevTopics | Best C# Blogs

Tuesday, December 11, 2007 5:55 AM by DevTopics | Best C# Blogs

Pingback from  DevTopics | Best C# Blogs

# [导入]Interesting Finds: 2007.12.13

Monday, December 17, 2007 7:30 PM by gOODiDEA

.NET: BestC#Blogs

C#3.0ObjectInitializersRevisited

C#ObjectInitialization

C#StableS...

# 给热爱学习的同学们推荐一些顶级的c# Blogs链接

Tuesday, February 19, 2008 8:48 AM by 无常

在TI行业,中文的资料永远都比英文的慢几个月,而且原创性的文章也少得可怜,有空时,不妨去这些英文技术BLOG溜达溜达,也许会有意外的惊喜。

# 给热爱学习的同学们推荐一些顶级的c# Blogs链接

Tuesday, February 19, 2008 9:44 AM by cnblogs.com

在IT行业,中文的资料永远都比英文的慢几个月,而且原创性的也少得可怜,有空时,不妨去这些英文技术BLOG溜达溜达,也许会有意外的惊喜。 好的C#博客应该符合这些条件: 有用的新闻、信息、技巧和代码例子

# Best C# Blogs : C# 411

Sunday, February 24, 2008 10:43 AM by Best C# Blogs : C# 411

Pingback from  Best C# Blogs : C# 411

# http://bartdesmet.net/blogs/bart/archive/2007/11/22/c-3-0-object-initializers-revisited.aspx

# Pattern Matching in C# - Part 6

Monday, April 14, 2008 10:22 AM by B# .NET Blog

Monday morning: The Return of The Pattern Matcher. After an awesome weekend (well, a Saturday at least

# ???????????? C# ?????????? ?? ???? ????????????&#8230; &laquo; ???????? ???????????? ??????????????

Pingback from  ???????????? C# ?????????? ?? ???? ????????????&#8230; &laquo; ???????? ???????????? ??????????????

# Block Object Initializers &laquo; Rum and Code

Friday, July 25, 2008 5:25 AM by Block Object Initializers « Rum and Code

Pingback from  Block Object Initializers &laquo; Rum and Code

# 给热爱学习的同学们推荐一些顶级的c# Blogs链接

Wednesday, September 03, 2008 2:38 AM by 布衣

在IT行业,中文的资料永远都比英文的慢几个月,而且原创性的也少得可怜,有空时,不妨去这些英文技术BLOG溜达溜达,也许会有意外的惊喜。 好的C#博客应该符合这些条件: 有用的新闻、信息、技巧和代码例子 定期更新 原创内容,不是广告文章盗用别人的文章 良好的组织,包含分类和tags 健康的讨论和读者评论 有一定的个人见解,最好还有点幽默感,但又不是自己在嗐吹牛

# ????????????????????????????????????????????????c# Blogs?????? &raquo; ??????

Pingback from  ????????????????????????????????????????????????c# Blogs?????? &raquo;  ??????

# ????????????????????????????????????????????????c# Blogs?????? | ??????

Pingback from  ????????????????????????????????????????????????c# Blogs?????? | ??????

# ????????????????????????????????????????????????c# Blogs?????? | ??????

Pingback from  ????????????????????????????????????????????????c# Blogs?????? | ??????

# C# da object initializer kullan??m?? &laquo; Koray K??rdinli

Tuesday, February 18, 2014 10:37 AM by C# da object initializer kullan??m?? « Koray K??rdinli

Pingback from  C# da object initializer kullan??m??  &laquo; Koray K??rdinli

# Object Initializers &raquo; Human-Debugger.net

Tuesday, March 11, 2014 2:51 PM by Object Initializers » Human-Debugger.net

Pingback from  Object Initializers &raquo; Human-Debugger.net