Skip to content

Instantly share code, notes, and snippets.

@dadhi
Last active January 13, 2016 10:48
Show Gist options
  • Save dadhi/11227982 to your computer and use it in GitHub Desktop.
Save dadhi/11227982 to your computer and use it in GitHub Desktop.
Proof of concept and very simple Multimethods implementation, that uses dynamic keyword from .Net 4.0. Thanks goes to <http://blogs.msdn.com/b/laurionb/archive/2009/08/13/multimethods-in-c-4-0-with-dynamic.aspx>.
using NUnit.Framework;
using Microsoft.CSharp.RuntimeBinder;
namespace MultiMethodsWithDymanic
{
[TestFixture]
public class MultimethodsTests
{
[Test]
public void What_is_good_for_rabbit_is_not_good_for_wolf()
{
var wolf = new Wolf();
wolf.Eat(new Apple());
Assert.That(wolf.State, Is.EqualTo(AnimalState.Bad));
wolf.Eat(new Meat());
Assert.That(wolf.State, Is.EqualTo(AnimalState.Good));
var rabbit = new Rabbit();
rabbit.Eat(new Apple());
Assert.That(rabbit.State, Is.EqualTo(AnimalState.Good));
rabbit.Eat(new Meat());
Assert.That(rabbit.State, Is.EqualTo(AnimalState.Bad));
}
[Test]
public void What_will_happen_when_suitable_method_is_not_found()
{
var wolf = new Wolf();
Assert.Throws<RuntimeBinderException>(() =>
wolf.Eat(new Milk()));
}
[Test]
public void Could_handle_unknown_or_default_case()
{
var rabbit = new Rabbit();
rabbit.Eat(new Milk());
Assert.That(rabbit.State, Is.EqualTo(AnimalState.Undefined));
}
}
public interface IMeal { }
public class Apple : IMeal { }
public class Meat : IMeal { }
public class Milk : IMeal { }
public enum AnimalState { Undefined, Bad, Good }
public interface IAnimal
{
AnimalState State { get; }
void Eat(IMeal meal);
}
public class Wolf : IAnimal
{
public AnimalState State { get; private set; }
public void Eat(IMeal meal)
{
EatMeal((dynamic)meal);
}
#region Implementation
private void EatMeal(Apple apple)
{
State = AnimalState.Bad;
}
private void EatMeal(Meat meat)
{
State = AnimalState.Good;
}
#endregion
}
public class Rabbit : IAnimal
{
public AnimalState State { get; private set; }
public void Eat(IMeal meal)
{
EatMeal((dynamic)meal);
}
#region Implementation
// Overall it is very similar to pattern matching.
/// <remarks>Handles unknown/default case.</remarks>>
private void EatMeal(IMeal meal)
{
State = AnimalState.Undefined;
}
private void EatMeal(Apple apple)
{
State = AnimalState.Good;
}
private void EatMeal(Meat meat)
{
State = AnimalState.Bad;
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment