[DynamicProxy] Creating an object that imports the properties of a class and implements an interface

3 views
Skip to first unread message

serious

unread,
Sep 15, 2009, 11:51:52 AM9/15/09
to Castle Project Users
Hello,

here is the situation : I have some business entities of type A, B,
C....
Now I would like to "add" to the entities another capability, a flag
"IsSelected", in order to use them in a context where it's needed.

Until now I've done this :
- creating an interface "ISelectableItem" that has two properties :
the flag "IsSelected" and the wrapped entity "Entity" :
public interface ISelectableItem
{
object Entity
{
get;
set;
}

bool IsSelected
{
get;
set;
}
}
- creating a factory that uses reflection to generate dynamic objects
that have the properties of a given business entity AND implement the
interface "ISelectableItem", and are in fact used through this
interface.

The factory simply receives an object that could be of type A, B or C
or whatever, and returns an "ISelectableItem" with the same properties
as the received entity.
The code is quite big, and uses "Reflection.Emit", so I'm just going
to describe the way I do it :
+ create a new TypeBuilder,
+ make it inherit from the type of the object,
+ make it implement the ISelectableItem interface,
+ add the properties "Entity" and "IsSelected" to effectively
implement the interface, and set the "Entity" property with a
reference to the original object.
+ import the other properties values from the original object into the
newly created object.

All this process is working fine but is completely "home-made" and
naive.

So I was wondering if the Castle's DynamicProxies could solve the same
problem in a more robust and reliable way ?

To sum up the problem : how to get "output" from "input" with :
- input : an object,
- output : an object with all the properties of "input" plus the
implementation of an interface ?


Thanks by advance.

Krzysztof Koźmic

unread,
Sep 16, 2009, 7:57:41 AM9/16/09
to castle-pro...@googlegroups.com
Yes, this is trivial with DP.

If all you need is a flag you do the following:

- Create interface ISelectable
- Create class Selectable which implements it
- Create proxy for your entities (class proxy) with new Selectable as
mixin for each entity instance.

voila!


Krzysztof

serious

unread,
Sep 16, 2009, 8:51:06 AM9/16/09
to Castle Project Users
Thanks a lot for your answer.

I've followed your directions and used your tutorial on mixins and
finally get the result.
But I'm not sure if there is a better way, particularly to improve the
way the properties values are imported in
"ImportPublicReadWritePropertiesValues".

- So here is the core, "ISelectable.cs" :
[code]using Castle.DynamicProxy;

namespace TestCastleDynamicProxy
{
public interface ISelectable
{
bool IsSelected
{
get;
set;
}
}

public class ISelectableFactory
{
private class SelectableDefaultImplementation : ISelectable
{
public bool IsSelected
{
get;
set;
}
}

private static readonly ProxyGenerator proxyGenerator;

static ISelectableFactory()
{
proxyGenerator = new ProxyGenerator();
}

public static ISelectable New(object entity)
{
ProxyGenerationOptions options = new ProxyGenerationOptions
();

options.AddMixinInstance(new
SelectableDefaultImplementation());

ISelectable selectableEntity =
proxyGenerator.CreateClassProxy(entity.GetType(), null, options) as
ISelectable;

selectableEntity.IsSelected = false;

selectableEntity.ImportPublicReadWritePropertiesValues
(entity);

return selectableEntity;
}
}
}[/code]
- It uses this extension class to import properties values,
"ReflectionExtensions.cs" :
[code]using System.Reflection;

namespace TestCastleDynamicProxy
{
public static class ReflectionExtensions
{
public static void ImportPublicReadWritePropertiesValues(this
object to, object from)
{
if (to != null && from != null)
{
foreach (PropertyInfo property in from.GetType
().GetProperties())
{
MethodInfo propertyGetter = property.GetGetMethod
();

// Ensure that the property can be retrieved from
the source, ie that it is not write-only
if (propertyGetter != null)
{
MethodInfo propertySetter = to.GetType
().GetProperty(property.Name).GetSetMethod();

// Ensure that the property can be set on the
target, ie that it is not read-only.
if (propertySetter != null)
{
propertySetter.Invoke(to, new object[]
{ propertyGetter.Invoke(from, null) });
}
}
}
}
}
}
}[/code]
- Some business entities, "Business.cs" :
[code]namespace TestCastleDynamicProxy
{
public class A
{
public int N
{
get;
set;
}
}

public class B
{
public int M
{
get;
set;
}
}
}[/code]
- And finally the mix of all these things, "Program.cs" :
[code]namespace TestCastleDynamicProxy
{
class Program
{
static void Main(string[] args)
{
A a = new A
{
N = 1
};

B b = new B
{
M = 1
};

ISelectable selectableA = ISelectableFactory.New(a);
selectableA.IsSelected = true;
int n = (selectableA as A).N;

ISelectable selectableB = ISelectableFactory.New(b);
int m = (selectableB as B).M;
}
}
}[/code]

The casts of "selectableA" and "selectableB" to "A" and "B"
respectively don't return "null" and "N" and "M" have the good values.


Please share your opinion.
Thanks again.

Krzysztof Koźmic

unread,
Sep 16, 2009, 9:53:26 AM9/16/09
to castle-pro...@googlegroups.com
Why are you doing this? (ImportPublicReadWritePropertiesValues)
Can't you use the mixed-in entities from the start?

Krzysztof

serious

unread,
Sep 17, 2009, 3:57:14 AM9/17/09
to Castle Project Users
[quote]Why are you doing this? (ImportPublicReadWritePropertiesValues)
[/quote]
Because I want the new object to have the same "public state" as the
provided one.

[quote]Can't you use the mixed-in entities from the start? [/quote]
If "from the start" means "from its instanciation", no I can't.
Actually, the users of the layer that will use "ISelectable" can
provide objects on which I have no control at all.
In the sample, "Business" and "Main" would be the user's layer : the
user creates the entities, initializes their states or do whatever he
wants with them and then passes them to my layer.
I'm aware it's not really robust because the "protected" and "private"
states of the entities will not be imported in the mixin.

Have I answered your question ?

Be that as it may, thanks again for your precious help.

Krzysztof Koźmic

unread,
Sep 17, 2009, 12:18:55 PM9/17/09
to castle-pro...@googlegroups.com
Ok, you have answered the question.

But what is the context that the Selectable property is used in?
Maybe keeping this in a proxy is not a good idea at all?
Would a simple dictionary mapping entity to it's selectable state be sufficient?

Krzysztof

serious

unread,
Sep 17, 2009, 2:18:17 PM9/17/09
to Castle Project Users
I'm using WPF and I have developped two DataGrid based components
which allow the user to select some entities.
WPF uses "data binding" to map the properties of the entities to the
properties of the graphical component.
So I've had to add a "IsSelected" property that maps to the "Checked"
state of "CheckBoxes" or "RadioButton", depending on the selection
mode supported by my DataGrids, of a selection column.
Moreover the real "IsSelectable" implementation wraps the state as
well as the entity, this way tracking the state of selection of each
entity is quite simple.

Krzysztof Koźmic

unread,
Sep 17, 2009, 2:58:53 PM9/17/09
to castle-pro...@googlegroups.com
I'm not a WPF expert so I don't know if you can override the DataBinding mechanism, to bind two entities to a single Row (which is what I would strive to do in this case), but I'm planning to add in next major version (v3) feature called Type Wrapping, that in conjunction with mixin we discussed already would give you precisely what you need (IMO): Take a look and tell me what you think, I'm looking for feedback and ideas:
http://using.castleproject.org/display/CASTLE/Dynamic+Proxy+3+design+meeting

Krzysztof

serious

unread,
Sep 17, 2009, 5:39:05 PM9/17/09
to Castle Project Users
I've posted a little message on the wiki, hope it's relevant.

By the way what's your opinion about the dynamic typing, will it solve
some problematics DynamicProxy solves now ?

Thanks for sharing.

On Sep 17, 8:58 pm, Krzysztof Koźmic <krzysztof.koz...@gmail.com>
wrote:
> I'm not a WPF expert so I don't know if you can override the DataBinding
> mechanism, to bind two entities to a single Row (which is what I would
> strive to do in this case), but I'm planning to add in next major
> version (v3) feature called Type Wrapping, that in conjunction with
> mixin we discussed already would give you precisely what you need (IMO):
> Take a look and tell me what you think, I'm looking for feedback and ideas:http://using.castleproject.org/display/CASTLE/Dynamic+Proxy+3+design+...
> ...
>
> read more >>

Krzysztof Koźmic

unread,
Sep 18, 2009, 1:19:16 AM9/18/09
to castle-pro...@googlegroups.com
Yes, it can solve some of the problems.
I'm even thinking on incorporating some of that in DynamicProxy itself after .NET 4.0 is released.

Same as with LINQ, it all boils down to how hard will it be to implement IMetaObjectProvider and the rest of the infrastructure, which I haven't really tried yet.
Reply all
Reply to author
Forward
0 new messages