c# Language request for properties

7 10 2008

Auto-Implemented properties are great, until you need to implement custom get or set logic. I love the ability to make the field an implementation detail, until you need to implement the property. What if you could continue to hide the field, like this:

public string FirstName {
  get {
    // do more stuff, like lazy init the field
    if (field == null)
      field = "Unknown";
    return field;
  }
  set {
    field = value;
  }
}

A new keyword, field, references the compiler generated property’s backing field. Also, for readonly fields:

public readonly string Id {
  get {
    return field;
  }
  set { // private is implied
    // do more stuff, like don’t accept null
    if (value == null)
      value = string.Empty;
    field = value;
  }
}

Where the property would need to be set in the constructor (like read-only fields) as the backing field would be marked read-only. For simplicity, the implementation would use simple property syntax while the compiled output would involve a read-only field, a truly read-only property and a constructor that executes the property’s set body via a static method call each time the field is set in the constructor.

Please rate and validate this sugestion at the MSDN Microsoft Product Feedback Center.



LINQ - WHERE X IN (…)

30 11 2007

I couldn’t figure out a way to perform the equivalent of WHERE Column1 IN ('A', 'B', 'C') in LINQ, where (’A', ‘B’, ‘C’) would represent an IEnumerable<T> where T is the type of Column1. So I thought it was an excellent time to write an extension method that would generate a dynamic expression tree that would add AND (Column1 == "A" OR Column1 = "B" OR ...) to the LINQ query. So I wrote the following code:

public static IQueryable<TSource> WhereIn<TSource, TKey> (
        this IQueryable<TSource> source1,
        Expression<Func<TSource, TKey>> keySelector,
        IEnumerable<TKey> source2) {
    if (null == source1)
        throw new ArgumentNullException ("source1");
    if (null == keySelector)
        throw new ArgumentNullException ("keySelector");
    if (null == source2)
        throw new ArgumentNullException ("source2");
    Expression where = null;
    foreach (TKey value in source2) {
        Expression equal = Expression.Equal (
                    keySelector.Body,
                    Expression.Constant (value, typeof (TKey))
                    );
        if (null == where)
            where = equal;
        else
            where = Expression.OrElse (where, equal);
    }
    return source1.Where<TSource> (
        Expression.Lambda<Func<TSource, bool>> (
            where, keySelector.Parameters));
}

An example of the usage:

var q = (from u in db.Users
    where u.LastLogin > new DateTime (2007, 5, 1)
    orderby u.LastLogin descending
    select new { u.FirstName, u.LastName, u.UserName, u.LastLogin }
    ).WhereIn (u => u.UserName, new string[] { "A", "B", "C" });

A day later, I found the right way that will actually generate “WHERE X IN (…)” in LINQ to SQL thanks to Mark Blomsma.



Internal NullReferenceException in HttpWebRequest when using a CachePolicy

15 03 2007

Setting the CachePolicy to the default HttpRequestCacheLevel causes an exception internal to HttpWebRequest when a web application is running with an application pool configured to use a custom identity. For example:

HttpWebRequest request = …;
request.CachePolicy =
  new System.Net.Cache.HttpRequestCachePolicy (
    System.Net.Cache.HttpRequestCacheLevel.Default);
request.GetResponse ();

GetResponse () throws a WebException: “The request was aborted: The request was canceled.” Inner exception shows that the private method CheckCacheUpdateOnResponse () of System.Net.HttpWebRequest encounters a NullReferenceException.

A “workaround” would involve loading the user’s profile. For example, if the application pool custom identity is DOMAIN\MyWebApp, log in to the server as MyWebApp. The error goes away – until the profile is unloaded.

This problem does not occur when the web application is using the default application pool identity, NetworkService, because I believe that profile is already loaded by default.

Another bug report is somewhat similar to this but only manifests after a few thousand requests. These are probably symptoms of a much larger bug (or design flaw – http request caching is currently implemented through IE’s cache).

Update: Microsoft has reproduced this bug and will be addressing it in a future release.