Tag-arkiv: c-sharp

Fancy Ruby stuff done in C#, part 3: dynamic properties

Please read this post for my reasons behind this article series.

Some people have asked me, why I try to do things in C# that are clearly Ruby-ideoms. The short answer is: Because I can. The longer answer involves thoughts about that you should never stop learning. For a programmer, this involves pushing your tools to their boundaries and beyond. Seeking new insights other places and apply them to your environment. Stuff like that.

Catch-all property (like Ruby’s method_missing)

One of the powerful features of Ruby is method_missing. With this seemingly innocent construct you are able to make a class respond to things that are not statically defined beforehand.

Typical uses are for ORMs like ActiveRecord, that enables you to map class properties to database table-fields without explicitly defining the fieldnames in your class.

The way ActiveRecord does this is, that the model base-class contains a Hash (Dictionary) called attr. When a table-record is loaded, all fields are loaded into this hash. And method_missing are then used to map property-names directly to keys in the hash.

user = User.find(13)
puts user.email

This can also be done in C# using DynamicObject. http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.aspx

DynamicObject is a rather bold introduction into a strong-typed language like C#, since it expose members such as properties and methods at run time, instead of at compile time.

using System;
using System.Collections.Generic;
using System.Dynamic;

public class MyFakeORM : DynamicObject {
    // For a clearer example, I don't go into the stuff about loading data from the database into this model

    // Dictionary to hold all fields from the loaded record
    Dictionary _attr = new Dictionary();

    // Catch-all methods for getting and setting a "missing" property
    public override bool TrySetMember(SetMemberBinder binder, object value) {
        _attr[binder.Name] = value;
        return true;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result) {
        return _attr.TryGetValue(binder.Name, out result);
    }
}


Note: For this to work, you also need to define your instance-variable as a dynamic instead of MyFakeORM:

dynamic user = new MyFakeORM();

user.email = "carsten@sarum.dk";

Console.WriteLine(user.email);

If you want to enable access with both properties as shown above AND as a common Dictionary, you need to add setters and getters for the class:

using System;
using System.Collections.Generic;
using System.Dynamic;

public class MyFakeORM : DynamicObject {
    ...

    public object this[string key] {
        get {
            return _attr[key];
        }
        set {
            _attr[key] = value;
        }	
    }	

    ...
    // The rest is as before
}

Now all of the following is valid:

dynamic user = new MyFakeORM();

user.email = "carsten@sarum.dk";
user['email'] = "carsten@sarum.dk";

Console.WriteLine(user.email);
Console.WriteLine(user['email']);
Bookmark and Share

Fancy Ruby stuff done in C#, part 2: flash messages

Please read this post for my reasons behind this article series.

Using flash messages between web requests

Ok I admit, this is not entirely a C# vs. Ruby issue. It is more Ruby On Rails done with MVC3. But it uses some of the dynamic stuff from C#.

In Rails you can push messages between requests by using a special flash component:

controller UserController < ApplicationController

def Login
  user = (try-to-login-user)
  if not user.LoggedIn?
    flash[:error] = “Invalid credentials”
    redirect_to :controller => “LoginForm”
  end
end
…

This will use sessions to carry the error-message into the next request. You can now test for the flash-message in LoginForm's view:

Login

<% if flash[:error] %>
<%=flash[:error]%>
<% end %>

After this request, the flash message is erased automatically.

The same thing can be made in .NET by using a combination of the dictionary TempData" and C#'s extension methods. And we can formalize it a bit more by using an enum to control how many different message types, that we will accept.

Create a file called "FlashHelper.cs" with the following content:

using System;
using System.Collections.Generic;
using System.Text;

namespace System.Web.Mvc
{
    public enum FlashType
    {
            Info,
            Warning,
            Error
    }

    public class FlashData
    {
        public FlashType Key { get; set; }
        public string Message { get; set; }
    }

    public static class FlashHelpers
    {
        public static void Flash(this Controller controller, FlashType key, string message)
        {
            if (controller.TempData["flash"] == null)
                controller.TempData["flash"] = new List<FlashData>();

            var flashList = controller.TempData["flash"] as List<FlashData>;
            flashList.Add(new FlashData {Key = key, Message = message});
        }

        public static MvcHtmlString Flash(this HtmlHelper helper)
        {
            var sb = new StringBuilder();

            if (helper.ViewContext.TempData["flash"] != null)
            {
                foreach (FlashData flash in helper.ViewContext.TempData["flash"] as List<FlashData>)
                {
                    sb.AppendLine(string.Format("<div class=\"flash {0}\">", flash.Key.ToString().ToLower()));
                    sb.AppendLine(flash.Message);
                    sb.AppendLine("</div>");
                }
            }
            return MvcHtmlString.Create(sb.ToString());
        }
    }
}

What I am doing here is, that I extend the base MVC controller with a new method called "Flash()". You call this in your controller to set a new message, supplying the type of message and the message-string itself.

The same goes for extending the Html helper. I define a method, that will print out all added messages, each of them wrapped into their own DIV tag with classes set appropiate of the message type.

So now we can write a C# MVC 3 example like the Rails one above.

The controller:

public class UserController : Controller
{
  public RedirectToRouteResult DoLogin(string username, string password)
  {
    var user = (try-to-login-user);

    if (!user.LoggedIn()) {
      this.Flash(FlashType.Error, "Invalid credentials");
      return RedirectToAction("LoginForm");
    }
    ...

And in your _layout.cshtml view:

@Html.Flash() @RenderBody()

If this example is run, and the user tries to login with invalid credentials, the @Html.Flash() call will render:

Invalid credentials
...

which you can then style with CSS.

Bookmark and Share

Fancy Ruby stuff done in C#, part 1: extension methods

Ruby is a very dynamic language, and you are able to do a lot of stuff with class extensions, meta programming, lambda functions and so forth. When I first experienced Ruby back in 2006 I was very impressed with some of the stuff possible – things that IMHO made C# look stale and static.

Not so any more. The recent updates to C# in 2008 (with .NET 3.5) and lately with .NET 4.0 has added functionality, that enables a more dynamic approach to C# programming, while still keeping the safety net of a strongly typed compiled language.

This is the first part of a small series, where I will take some of the goodies from Ruby and explain how to do it in C#.

Extending classes without subclassing

Most people a first exposed to Ruby through the web framework Ruby on Rails (Rails for short). Rails does a number of cool tricks. One of them is in the ActiveSupport part where the Integer class is extended with some extra methods called days(), weeks(), months(), and years(). This enables some “wow” effects when first looking at Rails code. You are able to do stuff like this:

short_period = 10.days
  => returns a Fixnum with value 864.000 (10 days in seconds)

10.days.to_s
  => returns the string "10 days"

long_period = 3.weeks
  => returns a Fixnum with value 1.814.400 (21 days in seconds)

And even create dates like this

realistic_deadline = 2.weeks.from_now

original_deadline = 5.days.ago

Doing this in C#

This stuff is not originally built into Ruby. The authors of Rails extended the Fixnum class with methods these methods. This is also doable in C#:

public static class IntegerExtensions
{
    public static Days Days(this int days)
        { return new Days(days); }
    public static Weeks Weeks(this int weeks)
        { return new Weeks(weeks); }
    public static Months Months(this int months)
        { return new Months(months); }
}

This introduces 3 new classes, that I will create now:

public class Days
{
    private int days;

    public Days(int d)
        { days = d; }

    public override string ToString()
        { return string.Format("{0} days", days); }

    public DateTime Ago()
        { return DateTime.Today.AddDays(-days); }

    public DateTime FromNow()
        { return DateTime.Today.AddDays(days); }
}

public class Weeks
{
    private int weeks;

    public Weeks(int w)
        { weeks = w; }

    public override string ToString()
        { return string.Format("{0} weeks", weeks); }

    public DateTime Ago()
        { return DateTime.Today.AddDays(-7 * weeks); }

    public DateTime FromNow()
        { return DateTime.Today.AddDays(7 * weeks); }
}

public class Months
{
    private int months;

    public Months(int m)
        { months = m; }

    public override string ToString()
        { return string.Format("{0} months", months); }

    public DateTime Ago()
        { return DateTime.Today.AddMonths(-months); }

    public DateTime FromNow()
        { return DateTime.Today.AddMonths(months); }
}

With these into place I can do this

Console.WriteLine(10.Days().ToString());
Console.WriteLine("{0}", 10.Days().Ago());
Console.WriteLine("{0}", 10.Days().FromNow());

DateTime originalDeadline = 2.Weeks().Ago();

DateTime realisticDeadline = 3.Months().FromNow();

Pretty neat, huh? If only we could loose the parantheses when calling the methods, but I guess we can’t have all. :-)

Continue to part 2.

Bookmark and Share