In the hallways of building 42, several of us have talked about how often we need to hard-code member names as strings in code, but we always feel like there should be some language operator to do this.  We’ve specifically said there should be a memberof() in C# the same way there’s a typeof() operator.

I got tired of waiting for it though, and decided to see how closely I could come to creating this behavior.  What sparked it was my usage of NHibernate’s Restrictions class tonight.  I was looking at a post on Ayende’s blog showing examples of queries such as the following:

var blogs = s.CreateCriteria<Blog>()
    .Add(Restrictions.Disjunction()
             .Add(Restrictions.Eq("Title", "Ayende @ Rahien"))
             .Add(Restrictions.Eq("Subtitle", "Send me a patch for that")))
    .List<Blog>();

The hard-coded strings just make me sad; probably more so than they should, but I can’t help it.  Here’s what I really want to see:

var blogs = s.CreateCriteria<Blog>()
    .Add(Restrictions.Disjunction()
             .Add(Restrictions.Eq(memberof(Blog.Title), "Ayende @ Rahien"))
             .Add(Restrictions.Eq(memberof(Blog.Subtitle), "Send me a patch for that")))
    .List<Blog>();

I obviously can’t add a memberof operator, and I also can’t make Blog.Title or Blog.Subtitle work.  But this isn’t too far off:

Blog blog = null;
 
var blogs = s.CreateCriteria<Blog>()
    .Add(Restrictions.Disjunction()
             .Add(Restrictions.Eq(Member.Of(() => blog.Title), "Ayende @ Rahien"))
             .Add(Restrictions.Eq(Member.Of(() => blog.Subtitle), "Send me a patch for that")))
    .List<Blog>();

It’s a bit more verbose, but the member is now checked at compile time.  Here’s a link to the unit tests that I have for my Member class: http://codepaste.net/t3oznt.  And here’s the link to the current code for this Member class: http://codepaste.net/tfwmsu.

Here are my favorite tests:

[TestMethod]
public void CanGetMemberInfo()
{
    Patron patron = null;
    MemberInfo member = Member.Of(() => patron.FirstName);
 
    Assert.IsInstanceOfType(member, typeof(MemberInfo));
    Assert.AreEqual<string>("FirstName", member.Name);
}
 
[TestMethod]
public void CanGetMemberAsString()
{
    Patron patron = null;
    string member = Member.Of(() => patron.FirstName);
 
    Assert.AreEqual<string>("FirstName", member);
}
[TestMethod]
public void PropertyChangedEventArgsIsEasy()
{
    PropertyChangedEventArgs args = new PropertyChangedEventArgs(Member.Of(() => this.SomeProperty));
    Assert.AreEqual<string>("SomeProperty", args.PropertyName);
}
 
[TestMethod]
public void RaisePropertyChangedIsEasy()
{
    string propertyName = this.RaisePropertyChanged(Member.Of(() => this.SomeProperty));
    Assert.AreEqual<string>("SomeProperty", propertyName);
}
 
public string SomeProperty { get; set; }
private string RaisePropertyChanged(string propertyName)
{
    return propertyName;
}


Glenn and I had previously created a RaisePropertyChanged() method that accepted an Expression<Func<object>> to do this same thing basically, but I really like having Member.Of() as a general-purpose method that will implicitly convert to either a string or a MemberInfo, allowing me to use it anywhere that I need to specify a member name or info.

So now that I’m all excited about this, please burst my bubble and tell me why I shouldn’t do this. But if you like the idea of a memberof() being built into the language to do this, do speak up.  Maybe we’ll convince Anders of it!