<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Ivan Zlatev &#187; LINQ</title>
	<atom:link href="http://ivanz.com/tag/linq/feed/" rel="self" type="application/rss+xml" />
	<link>http://ivanz.com</link>
	<description></description>
	<lastBuildDate>Sat, 05 Jun 2010 16:19:20 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>How to avoid passing property names as strings using C# 3.0 Expression Trees</title>
		<link>http://ivanz.com/2009/12/04/how-to-avoid-passing-property-names-as-strings-using-c-3-0-expression-trees/</link>
		<comments>http://ivanz.com/2009/12/04/how-to-avoid-passing-property-names-as-strings-using-c-3-0-expression-trees/#comments</comments>
		<pubDate>Fri, 04 Dec 2009 19:08:20 +0000</pubDate>
		<dc:creator>Ivan Zlatev</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[LINQ]]></category>
		<category><![CDATA[NHibernate]]></category>

		<guid isPermaLink="false">http://ivanz.com/?p=699</guid>
		<description><![CDATA[Referencing property names via strings is evil. Consider this simplistic example: private int _myProperty; public int MyProperty { get { return _myProperty; } set { _myProperty = value; NotifyPropertyChanged (this, &#34;MyProperty&#34;) } } // Somewhere in a different project or file... private void NotifyPropertyChanged (object sender, string propertyName) { if (propertyName == &#34;MyProperty&#34;) Console.WriteLine (&#34;Property [...]]]></description>
			<content:encoded><![CDATA[<p>Referencing property names via strings is evil. Consider this simplistic example:</p>
<pre class="brush: csharp;">
private int _myProperty;

public int MyProperty
{
    get { return _myProperty; }
    set {
        _myProperty = value;
        NotifyPropertyChanged (this, &quot;MyProperty&quot;)
    }
}

// Somewhere in a different project or file...
private void NotifyPropertyChanged (object sender, string propertyName)
{
    if (propertyName == &quot;MyProperty&quot;)
        Console.WriteLine (&quot;Property Changed&quot;);
}
</pre>
<p>If at some point the property gets renamed the code will compile fine but a bug will be introduced as all those strings that contain the property name will remain unchanged. Evil.</p>
<p>So I have been toying with NHibernate lately and yesterday I was writing some repositories. Let&#8217;s assume that theoretically they look like this:</p>
<pre class="brush: csharp;">
public class Repository &lt;TEntity&gt;
{
    public virtual TEntity FindById (object id)
    {
        ...
    }
}

public class UserRepository : Repository&lt;User&gt;
{
    public IList&lt;User&gt; FindByName (string name)
    {
        // query code
    }

    public IList&lt;User&gt; FindByEmail (string email)
    {
        // query code
    }
}
</pre>
<p>Both <em>FindByName </em>and <em>FindByEmail </em>in <em>UserRepository </em>will in theory contain the same queries but with different parameters. However I don&#8217;t really want to have to write individual queries so I considered a utility method:</p>
<pre class="brush: csharp;">
public class Repository &lt;TEntity&gt;
{
    public virtual TEntity FindById (object id)
    {
        ...
    }

    protected virtual IList&lt;TEntity&gt; FindByProperty (string propertyName, object value)
    {
        string columnName = NHibernateUtil.GetPropertyColumnName&lt;TEntity&gt; (propertyName);

        // Query here, e.g: &quot;SELECT .... WHERE .... columnName = value&quot; , etc.
    }
}

public class UserRepository : Repository&lt;User&gt;
{
    public IList&lt;User&gt; FindByName (string name)
    {
        return base.FindByProperty (&quot;Name&quot;, name);
    }

    public IList&lt;User&gt; FindByEmail (string email)
    {
        return base.FindByProperty (&quot;Email&quot;, email);
    }
}
</pre>
<p>Again this is very bad code and I hated the idea of it, so I sat down and started thinking. I remembered reading somewhere about C# 3.0 Expression Trees so I did some research. When using the special <em>Expression </em>type this seems to tell the compiler to create and expose an AST to us of e.g. a lambda function&#8217;s body, so if we pass a property reference expression we can parse the AST and extract the property name from there.</p>
<p>The theory in practice:</p>
<pre class="brush: csharp;">
public class UserRepository : Repository&lt;User&gt;
{
    public IList&lt;User&gt; FindByName (string name)
    {
        return base.FindByProperty (user =&gt; user.Name, name);
    }

    public IList&lt;User&gt; FindByEmail (string email)
    {
        return base.FindByProperty (user =&gt; user.Email, email);
    }
}

public class Repository &lt;TEntity&gt;
{
    public virtual TEntity FindById (object id)
    {
        ...
    }

    protected virtual IList&lt;TEntity&gt; FindByProperty (Expression&lt;Func&lt;TEntity, object&gt;&gt; propertyRefExpr,
                                                     object value)
    {
        string propertyName = GetPropertyName (propertyRefExpr);

        // Query code
    }

    private string GetPropertyName (Expression propertyRefExpr)
    {
        if (propertyRefExpr == null)
            throw new ArgumentNullException (&quot;propertyRefExpr&quot;, &quot;propertyRefExpr is null.&quot;);

        MemberExpression memberExpr = propertyRefExpr.Body as MemberExpression;
        if (memberExpr == null) {
            UnaryExpression unaryExpr = propertyRefExpr.Body as UnaryExpression;
            if (unaryExpr != null &amp;&amp; unaryExpr.NodeType == ExpressionType.Convert)
                memberExpr = unaryExpr.Operand as MemberExpression;
        }

        if (memberExpr != null &amp;&amp; memberExpr.Member.MemberType == MemberTypes.Property)
            return memberExpr.Member.Name;

        throw new ArgumentException (&quot;No property reference expression was found.&quot;,
                         &quot;propertyRefExpr&quot;);
    }
}
</pre>
<p>Also as a helper class:</p>
<pre class="brush: csharp;">
public static class PropertyUtil
{
    public static string GetPropertyName&lt;TObject&gt; (this TObject type,
                                                   Expression&lt;Func&lt;TObject, object&gt;&gt; propertyRefExpr)
    {
        return GetPropertyNameCore (propertyRefExpr.Body);
    }

    public static string GetName&lt;TObject&gt; (Expression&lt;Func&lt;TObject, object&gt;&gt; propertyRefExpr)
    {
        return GetPropertyNameCore (propertyRefExpr.Body);
    }

    private static string GetPropertyNameCore (Expression propertyRefExpr)
    {
        if (propertyRefExpr == null)
            throw new ArgumentNullException (&quot;propertyRefExpr&quot;, &quot;propertyRefExpr is null.&quot;);

        MemberExpression memberExpr = propertyRefExpr as MemberExpression;
        if (memberExpr == null) {
            UnaryExpression unaryExpr = propertyRefExpr as UnaryExpression;
            if (unaryExpr != null &amp;&amp; unaryExpr.NodeType == ExpressionType.Convert)
                memberExpr = unaryExpr.Operand as MemberExpression;
        }

        if (memberExpr != null &amp;&amp; memberExpr.Member.MemberType == MemberTypes.Property)
            return memberExpr.Member.Name;

        throw new ArgumentException (&quot;No property reference expression was found.&quot;,
                         &quot;propertyRefExpr&quot;);
    }
}
</pre>
<p>As you can see it contains two generic methods that operate either on types:</p>
<pre class="brush: csharp;">
string propertyName = PropertyUtil.GetName&lt;User&gt; (u =&gt; u.Email);
</pre>
<p>or instances:</p>
<pre class="brush: csharp;">
User user = GetUser();
string propertyName = user.GetPropertyName (u =&gt; u.Email);
</pre>
<p>Great, isn&#8217;t it? And safe to refactor.</p>
<p>Of course there is no such thing as a free lunch and the use of expression trees comes at the expense of some performance.</p>
<p>BTW is the font size of the code snippets sufficiently readable or is it too tiny?</p>
<p><strong>UPDATE:</strong> Added support for Convert expressions (implicit/explicit casting)</p>
]]></content:encoded>
			<wfw:commentRss>http://ivanz.com/2009/12/04/how-to-avoid-passing-property-names-as-strings-using-c-3-0-expression-trees/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
	</channel>
</rss>
