José F. Romaniello

Las aventuras y desventuras de un codificador.

Recently Krzysztof Koźmic has committed a patch to the DynamicProxy trunk that allows me to do a new trick. 
I will show you in this post a beautiful way to add behaviour to your entities.

I start defining this simple domain:

public interface IProduct
{
    int Id { get; }
    string Name { get; set; }
    double UnitPrice { get; set; }
}

public class Product : IProduct
{
    public int Id { get; set; }
    public string Name { get; set; }
    public double UnitPrice { get; set; }
}

public interface IEditableProduct : IProduct, INotifyPropertyChanged, IEditableObject
{}

Then I could generate a proxy as follows:

public IEditableProduct GenerateEditableModelOfProduct(Product product)
{
    var proxyGen = new ProxyGenerator();

    return (IEditableProduct)
        proxyGen.CreateInterfaceProxyWithTargetInterface(typeof (IProduct), 
                             new[] {typeof (IEditableProduct)},
                             product, 
                             new ProxyGenerationOptions(), 
                             new IInterceptor[]
                                 {
                                     new EditableObjectInterceptor(), 
                                     new PropertyChangeInterceptor()
                                 }
                             );

}
Let me improve it by adding generics:
public TEditableInterface 
    GenerateEditableModel<TEditableInterface, TDomainInterface>(TDomainInterface entity)
    where TEditableInterface : INotifyPropertyChanged, IEditableObject, TDomainInterface
{
    var proxyGen = new ProxyGenerator();

    return (TEditableInterface)
        proxyGen.CreateInterfaceProxyWithTargetInterface(typeof(TDomainInterface), 
                             new[] {typeof (TEditableInterface)},
                             entity, 
                             new ProxyGenerationOptions(), 
                             new IInterceptor[]
                                 {
                                     new EditableObjectInterceptor(), 
                                     new PropertyChangeInterceptor()
                                 }
                             );
}

Note: you can take EditableObjectInterceptor and PropertyChangeInterceptor from unhaddins.examples.
And now the test:

[Test]
public void TestEditableBehaviour()
{
    var product = new Product()
                      {
                          Name = "Potatoes"
                      };

    var editableProductModel = GenerateEditableModel<IEditableProduct, IProduct>(product);
    editableProductModel.Name.Should().Be.EqualTo("Potatoes");
    
    editableProductModel.BeginEdit();
    editableProductModel.Name = "Apple";
    editableProductModel.Name.Should().Be.EqualTo("Apple");
    editableProductModel.CancelEdit();

    editableProductModel.Name.Should().Be.EqualTo("Potatoes");

    editableProductModel.BeginEdit();
    editableProductModel.Name = "Succory";
    editableProductModel.Name.Should().Be.EqualTo("Succory");
    editableProductModel.EndEdit();

    editableProductModel.Name.Should().Be.EqualTo("Succory");
}
[Test]
public void TestNotificableBehaviour()
{
    var product = new Product()
    {
        Name = "Potatoes"
    };
    bool eventWasCalled = false; 
    
    var editableProductModel = GenerateEditableModel<IEditableProduct, IProduct>(product);
    editableProductModel.PropertyChanged += (sender, args) =>
                                                {
                                                    if (args.PropertyName == "Name")
                                                        eventWasCalled = true;
                                                };
    editableProductModel.UnitPrice = 2.2;

    eventWasCalled.Should().Be.False();
    
    editableProductModel.Name = "Succory";

    eventWasCalled.Should().Be.True();
}

If you read my two previous post you will find a way to work with NHibernate as follows:

Session.Get<IProduct>(1);
//or:
Session.Get<IEditableProduct>(1);

kick it on DotNetKicks.com

| More

0 comentarios:

Publicar un comentario en la entrada