Passing Properties to Generics

G

Guest

I am trying to create a generic Command object (following the Command design
pattern) that allows me to specify a generic type, an object to operate on,
and most importantly, a public Property on that object for getting and
setting the value in question.

Currently the only approach I've found to work is to use delegates along
with Get and Set functions (instead of using a Property). See code below.

Anyone have a better approach than what I have as follows?


class Person
{
private string name = "";
private int age = 0;

public string Name { set { name = value; } get { return name; } }
public int Age { set { age = value; } get { return age; } }

// These needed to be added to get the Generic PersonCommand to work
public void SetName(string Name) { name = Name; }
public string GetName() { return name; }
}


abstract class Command
{
public abstract void Do();
public abstract void Undo();
}


class PersonCommand<T> : Command
{
private Person person = null;
private T oldValue;
private T newValue;
private SetPersonValue setPersonValue;
private GetPersonValue getPersonValue;

// These are needed because I can't work with Properties
public delegate void SetPersonValue(T value);
public delegate T GetPersonValue();

public PersonCommand(Person P, SetPersonValue setValue,
GetPersonValue getValue,
T NewValue)
{
setPersonValue = setValue;
getPersonValue = getValue;

oldValue = getPersonValue();
newValue = NewValue;
person = P;
}

public override void Do()
{
setPersonValue(newValue);
// Would prefer to do the following:
// person.??? = newValue;
}

public override void Undo()
{
setPersonValue(oldValue);
}
}


public void test()
{
Person Robert = new Person();
Robert.Name = "Robert";
Robert.Age = 30;

PersonCommand<string> name2Command = new
PersonCommand<string>(Robert, new
PersonCommand<string>.SetPersonValue(Robert.SetName),
new PersonCommand<string>.GetPersonValue(Robert.GetName),
"Bobby");

name2Command.Do();
Debug.WriteLine("Name = " + Robert.Name);
name2Command.Undo();
Debug.WriteLine("Name = " + Robert.Name);

}
 
J

Jay B. Harlow [MVP - Outlook]

Jeff,
Have you considered using a PropertyDescriptor instead of a Delegate?

http://msdn.microsoft.com/library/d...omponentmodelpropertydescriptorclasstopic.asp

Your Command object would accept the type of the Component (Person), the
Type of Property and the name of the Property, it could then use
TypeDescriptro.GetProperties to lookup the PropertyDescriptor for that
field. I would consider making the first type type parameters, while the
third would be a parameter to the constructor.

http://msdn.microsoft.com/library/d...odelTypeDescriptorClassGetPropertiesTopic.asp

Then Get & Set would then use PropertyDescriptor.GetValue &
PropertyDescriptor.SetValue to change the values...

Something like (untested, not syntax checked):

class GenericCommand<TComponent, TProperty> : Command
{
private TComponent person = null;
private PropertyDescriptor descriptor = null;
private TProperty oldValue;
private TProperty newValue;

public GenericCommand(TComponent P, String property,
TProperty NewValue)
{
descriptor =
TypeDescriptor.GetProperties(typeof(TComponent))[property];
person = P;
oldValue = Value;
newValue = NewValue;
}

public TProperty Value
{
get
{
return (TProperty)descriptor.GetValue(person);
{
set
{
descriptor.SetValue(person, value);
}
}

public override void Do()
{
Value = newValue;
}

public override void Undo()
{
Value = oldValue;
}
}

Even without the other stuff, you could base the Value Property on your
GetPersonValue & SetPersonValue delegates...

Hope this helps
Jay


|I am trying to create a generic Command object (following the Command
design
| pattern) that allows me to specify a generic type, an object to operate
on,
| and most importantly, a public Property on that object for getting and
| setting the value in question.
|
| Currently the only approach I've found to work is to use delegates along
| with Get and Set functions (instead of using a Property). See code below.
|
| Anyone have a better approach than what I have as follows?
|
|
| class Person
| {
| private string name = "";
| private int age = 0;
|
| public string Name { set { name = value; } get { return name; } }
| public int Age { set { age = value; } get { return age; } }
|
| // These needed to be added to get the Generic PersonCommand to
work
| public void SetName(string Name) { name = Name; }
| public string GetName() { return name; }
| }
|
|
| abstract class Command
| {
| public abstract void Do();
| public abstract void Undo();
| }
|
|
| class PersonCommand<T> : Command
| {
| private Person person = null;
| private T oldValue;
| private T newValue;
| private SetPersonValue setPersonValue;
| private GetPersonValue getPersonValue;
|
| // These are needed because I can't work with Properties
| public delegate void SetPersonValue(T value);
| public delegate T GetPersonValue();
|
| public PersonCommand(Person P, SetPersonValue setValue,
| GetPersonValue getValue,
| T NewValue)
| {
| setPersonValue = setValue;
| getPersonValue = getValue;
|
| oldValue = getPersonValue();
| newValue = NewValue;
| person = P;
| }
|
| public override void Do()
| {
| setPersonValue(newValue);
| // Would prefer to do the following:
| // person.??? = newValue;
| }
|
| public override void Undo()
| {
| setPersonValue(oldValue);
| }
| }
|
|
| public void test()
| {
| Person Robert = new Person();
| Robert.Name = "Robert";
| Robert.Age = 30;
|
| PersonCommand<string> name2Command = new
| PersonCommand<string>(Robert, new
| PersonCommand<string>.SetPersonValue(Robert.SetName),
| new PersonCommand<string>.GetPersonValue(Robert.GetName),
| "Bobby");
|
| name2Command.Do();
| Debug.WriteLine("Name = " + Robert.Name);
| name2Command.Undo();
| Debug.WriteLine("Name = " + Robert.Name);
|
| }
|
|
|
 
J

Jay B. Harlow [MVP - Outlook]

Hmm...

| field. I would consider making the first type type parameters, while the
That should be "the first two type parameters, while the"...

Also looking at it just now; the TComponent type parameter is not
specifically needed (GetProperties can accept either an object or a type),
although TComponent does bind GenericCommand to Person which could be
nice...

Hope this helps
Jay

| Jeff,
| Have you considered using a PropertyDescriptor instead of a Delegate?
|
|
http://msdn.microsoft.com/library/d...omponentmodelpropertydescriptorclasstopic.asp
|
| Your Command object would accept the type of the Component (Person), the
| Type of Property and the name of the Property, it could then use
| TypeDescriptro.GetProperties to lookup the PropertyDescriptor for that
| field. I would consider making the first type type parameters, while the
| third would be a parameter to the constructor.
|
|
http://msdn.microsoft.com/library/d...odelTypeDescriptorClassGetPropertiesTopic.asp
|
| Then Get & Set would then use PropertyDescriptor.GetValue &
| PropertyDescriptor.SetValue to change the values...
|
| Something like (untested, not syntax checked):
|
| class GenericCommand<TComponent, TProperty> : Command
| {
| private TComponent person = null;
| private PropertyDescriptor descriptor = null;
| private TProperty oldValue;
| private TProperty newValue;
|
| public GenericCommand(TComponent P, String property,
| TProperty NewValue)
| {
| descriptor =
| TypeDescriptor.GetProperties(typeof(TComponent))[property];
| person = P;
| oldValue = Value;
| newValue = NewValue;
| }
|
| public TProperty Value
| {
| get
| {
| return (TProperty)descriptor.GetValue(person);
| {
| set
| {
| descriptor.SetValue(person, value);
| }
| }
|
| public override void Do()
| {
| Value = newValue;
| }
|
| public override void Undo()
| {
| Value = oldValue;
| }
| }
|
| Even without the other stuff, you could base the Value Property on your
| GetPersonValue & SetPersonValue delegates...
|
| Hope this helps
| Jay
|
|
| ||I am trying to create a generic Command object (following the Command
| design
|| pattern) that allows me to specify a generic type, an object to operate
| on,
|| and most importantly, a public Property on that object for getting and
|| setting the value in question.
||
|| Currently the only approach I've found to work is to use delegates along
|| with Get and Set functions (instead of using a Property). See code
below.
||
|| Anyone have a better approach than what I have as follows?
||
||
|| class Person
|| {
|| private string name = "";
|| private int age = 0;
||
|| public string Name { set { name = value; } get { return name; } }
|| public int Age { set { age = value; } get { return age; } }
||
|| // These needed to be added to get the Generic PersonCommand to
| work
|| public void SetName(string Name) { name = Name; }
|| public string GetName() { return name; }
|| }
||
||
|| abstract class Command
|| {
|| public abstract void Do();
|| public abstract void Undo();
|| }
||
||
|| class PersonCommand<T> : Command
|| {
|| private Person person = null;
|| private T oldValue;
|| private T newValue;
|| private SetPersonValue setPersonValue;
|| private GetPersonValue getPersonValue;
||
|| // These are needed because I can't work with Properties
|| public delegate void SetPersonValue(T value);
|| public delegate T GetPersonValue();
||
|| public PersonCommand(Person P, SetPersonValue setValue,
|| GetPersonValue getValue,
|| T NewValue)
|| {
|| setPersonValue = setValue;
|| getPersonValue = getValue;
||
|| oldValue = getPersonValue();
|| newValue = NewValue;
|| person = P;
|| }
||
|| public override void Do()
|| {
|| setPersonValue(newValue);
|| // Would prefer to do the following:
|| // person.??? = newValue;
|| }
||
|| public override void Undo()
|| {
|| setPersonValue(oldValue);
|| }
|| }
||
||
|| public void test()
|| {
|| Person Robert = new Person();
|| Robert.Name = "Robert";
|| Robert.Age = 30;
||
|| PersonCommand<string> name2Command = new
|| PersonCommand<string>(Robert, new
|| PersonCommand<string>.SetPersonValue(Robert.SetName),
|| new PersonCommand<string>.GetPersonValue(Robert.GetName),
|| "Bobby");
||
|| name2Command.Do();
|| Debug.WriteLine("Name = " + Robert.Name);
|| name2Command.Undo();
|| Debug.WriteLine("Name = " + Robert.Name);
||
|| }
||
||
||
|
|
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top