Design question

O

Omatase

I have a bunch of entity classes with just a whole bunch of properties
in it. I have to count each time one of these properties is read and
written to. I was hoping I could implement a pattern that would allow
me to do that easily so that I didn't have to write custom setters and
getters for each property (I'm using automatic properties for
convenience). Does anyone have any idea how I might be able to do this
easily?

The more I think about it the more it seems unlikely there is any
other solution. My mind keeps veering toward events when I try to
decide how I might easily do this but that's definitely not it. This
post is just hoping there is something I haven't thought of.
 
K

kndg

I have a bunch of entity classes with just a whole bunch of properties
in it. I have to count each time one of these properties is read and
written to. I was hoping I could implement a pattern that would allow
me to do that easily so that I didn't have to write custom setters and
getters for each property (I'm using automatic properties for
convenience). Does anyone have any idea how I might be able to do this
easily?

The more I think about it the more it seems unlikely there is any
other solution. My mind keeps veering toward events when I try to
decide how I might easily do this but that's definitely not it. This
post is just hoping there is something I haven't thought of.

I don't think it is possible. So, you would have to write a custom
getter/setter and implement the INotifyPropertyChanged interface. I'm
also interested to know if it really can be done (through reflection or
something), though I don't know whether it could give any value.
 
P

Peter Duniho

Omatase said:
I have a bunch of entity classes with just a whole bunch of properties
in it. I have to count each time one of these properties is read and
written to. I was hoping I could implement a pattern that would allow
me to do that easily so that I didn't have to write custom setters and
getters for each property (I'm using automatic properties for
convenience). Does anyone have any idea how I might be able to do this
easily?

Some possibilities:

– Instead of declaring the classes themselves, use some kind of
code-generation implementation that can auto-generate the classes based
on some template and type description you provide. Then, the inability
to use automatic properties would not be an impediment to your workflow.

– Use Visual Studio code snippets to accomplish something like the above.

– Use reflection to access the properties from a wrapper, keeping a
count in the wrapper

– Instead of properties, use an indexer that takes an enum or string
as the index, mapping the property identifier to a dictionary entry, and
handling the counting in the dictionary.

– Similar to the above, except still have the actual properties, and
implement them using an indexer-like helper class. You can't use
automatic properties in that approach, but at least the implementation
would be trivial.

– Use one of the code-rewriting tools (unfortunately, I don't have
specifics…not something I use personally) to inject your own
access-counting logic into the properties.

– Change the program requirements so that you don't actually need to
know how many times a given property has been read or written.

My preferred solution would be the last one. The number of times a
property's been accessed doesn't seem like a generally useful thing for
a program to need to know.

You mentioned using events as an alternative. I don't see how events
can help reduce the implementation cost, but it could very well be that
there is some value to including events in the overall design. Without
more specifics as to what led you to this design and the context in
which it's going to be used, I can't really say though.

Pete
 
O

Omatase

Some possibilities:

   – Instead of declaring the classes themselves, use some kind of
code-generation implementation that can auto-generate the classes based
on some template and type description you provide.  Then, the inability
to use automatic properties would not be an impediment to your workflow.

   – Use Visual Studio code snippets to accomplish something like the above.

   – Use reflection to access the properties from a wrapper, keeping a
count in the wrapper

   – Instead of properties, use an indexer that takes an enum or string
as the index, mapping the property identifier to a dictionary entry, and
handling the counting in the dictionary.

   – Similar to the above, except still have the actual properties,and
implement them using an indexer-like helper class.  You can't use
automatic properties in that approach, but at least the implementation
would be trivial.

   – Use one of the code-rewriting tools (unfortunately, I don't have
specifics…not something I use personally) to inject your own
access-counting logic into the properties.

   – Change the program requirements so that you don't actually need to
know how many times a given property has been read or written.

My preferred solution would be the last one.  The number of times a
property's been accessed doesn't seem like a generally useful thing for
a program to need to know.

You mentioned using events as an alternative.  I don't see how events
can help reduce the implementation cost, but it could very well be that
there is some value to including events in the overall design.  Without
more specifics as to what led you to this design and the context in
which it's going to be used, I can't really say though.

Pete

I notice you had a suggestion that included a wrapper class. This is
something else that just came to my mind as well. This might be the
way to go. This will let me count the access to those properties
without having to put the functionality in the properties themseleves.

The reason I have such a strange requirement is that I'm making a game
where I will be keeping track of these numbers and persisting them to
a database as a statistic that will be available at some future point
to use in formulae.
 
P

Peter Duniho

Omatase said:
[...]
The reason I have such a strange requirement is that I'm making a game
where I will be keeping track of these numbers and persisting them to
a database as a statistic that will be available at some future point
to use in formulae.

And what makes that statistic valuable? Is it really worth convoluting
the design of the program just to accommodate that goal? And if the
statistic is so valuable, why isn't it worthwhile to just go ahead and
write a per-property implementation, rather than going after some
harder-to-maintain solution?

It's your program, and I'm not about to try to argue the point. The
above are simply some questions that hopefully give you food for thought
as you head down this path, so that if you do continue to pursue it, you
at least do so with some confidence that it's worth doing.

Personally, I'm skeptical. But if everyone always agreed with me, life
would be pretty boring. :)

Pete
 
O

Omatase

Omatase said:
[...]
The reason I have such a strange requirement is that I'm making a game
where I will be keeping track of these numbers and persisting them to
a database as a statistic that will be available at some future point
to use in formulae.

And what makes that statistic valuable?  Is it really worth convoluting
the design of the program just to accommodate that goal?  And if the
statistic is so valuable, why isn't it worthwhile to just go ahead and
write a per-property implementation, rather than going after some
harder-to-maintain solution?

It's your program, and I'm not about to try to argue the point.  The
above are simply some questions that hopefully give you food for thought
as you head down this path, so that if you do continue to pursue it, you
at least do so with some confidence that it's worth doing.

Personally, I'm skeptical.  But if everyone always agreed with me, life
would be pretty boring.  :)

Pete

Thanks for your help!
 
A

Andy O'Neill

The reason I have such a strange requirement is that I'm making a game
where I will be keeping track of these numbers and persisting them to
a database as a statistic that will be available at some future point
to use in formulae.

Are you counting when something or other is done rather than just access to
the property?
Could you use wpf (like) command routing to count the calls to commands
rather than the specific properties?

I can't help but think maybe you're coming at the problem from the wrong
direction somehow,
 
G

Gregory A. Beamer

Omatase said:
I have a bunch of entity classes with just a whole bunch of properties
in it. I have to count each time one of these properties is read and
written to. I was hoping I could implement a pattern that would allow
me to do that easily so that I didn't have to write custom setters and
getters for each property (I'm using automatic properties for
convenience). Does anyone have any idea how I might be able to do this
easily?

The more I think about it the more it seems unlikely there is any
other solution. My mind keeps veering toward events when I try to
decide how I might easily do this but that's definitely not it. This
post is just hoping there is something I haven't thought of.

I disagree it is not possible. Peter has suggested some ideas that could be
very helpful. The code generation idea is fairly simple. You create the
recipe for the "cookies" and then the oven (generator) and you can repeat
for all entities. You can also adorn source code files by looking at
properties already created with a "code fixer" type of generator.

If you can force people to adjust the object through a framework, you could
also do some creative things with attributes, but I digress. Actually, this
is a lot like the wrapper class idea.

I also question, like Peter, why the number of sets and gets is important.

--
Peace and Grace,
Greg

Twitter: @gbworld
Blog: http://gregorybeamer.spaces.live.com

************************************************
| Think outside the box! |
************************************************
 
G

Gregory A. Beamer

Peter Duniho said:
Personally, I'm skeptical. But if everyone always agreed with me, life
would be pretty boring. :)

I don't think you are in danger of that with me around. ;-)

Actually, I do agree with you on this one, however. I am sure there is
something deeper, like a missing persistence call (trying to keep the object
in memory and count changes when it is later persisted?), rather than saving
as the person changes it. If it is truly, the guy can change his mind 20
times before saving, why is the knowledge he did that important?

--
Peace and Grace,
Greg

Twitter: @gbworld
Blog: http://gregorybeamer.spaces.live.com

************************************************
| Think outside the box! |
************************************************
 
A

Arne Vajhøj

I have a bunch of entity classes with just a whole bunch of properties
in it. I have to count each time one of these properties is read and
written to. I was hoping I could implement a pattern that would allow
me to do that easily so that I didn't have to write custom setters and
getters for each property (I'm using automatic properties for
convenience). Does anyone have any idea how I might be able to do this
easily?

The more I think about it the more it seems unlikely there is any
other solution. My mind keeps veering toward events when I try to
decide how I might easily do this but that's definitely not it. This
post is just hoping there is something I haven't thought of.

My suggestion would be to:
- make the properties virtual
- dynamicly generate a wrapper class that does the book keeping

A simple POC is attached below.

Arne

======================

using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

using Microsoft.CSharp;

namespace E
{
public class A
{
public virtual int Iv { get; set; }
public virtual string Sv { get; set; }
}
public class B
{
public virtual int Iv { get; set; }
public virtual double Xv { get; set; }
}
public interface IWrapper
{
int CountGets(string prop);
int CountSets(string prop);
}
public class WrapperGen
{
private Dictionary<Type, Type> cache = new Dictionary<Type,
Type>();
private const string nstemp = @"using System;
using E;

namespace WrapperGen
{{
{0}
}}
";
private const string clztemp = @" public class {0} : {1},
IWrapper
{{
{2}
}}
";
private const string fldtemp = @" private {0} del;
";
private const string contemp = @" public {0}({1} del)
{{
this.del = del;
}}
";
private const string proptemp = @" private int cGet{1} = 0;
private int cSet{1} = 0;
public override {0} {1}
{{
get
{{
cGet{1}++;
return del.{1};
}}
set
{{
cSet{1}++;
del.{1} = value;
}}
}}
";
private const string methgettemp = @" public int
CountGets(string prop)
{{
switch(prop)
{{
{0}
default:
throw new ArgumentException(prop + "" is not a
valid property"");
}}
}}
";
private const string lblgettemp = @" case ""{0}"":
return cGet{0};
break;
";
private const string methsettemp = @" public int
CountSets(string prop)
{{
switch(prop)
{{
{0}
default:
throw new ArgumentException(prop + "" is not a
valid property"");
}}
}}
";
private const string lblsettemp = @" case ""{0}"":
return cSet{0};
break;
";
private Type Create(Type t)
{
StringBuilder sb = new StringBuilder();
StringBuilder sbget = new StringBuilder();
StringBuilder sbset = new StringBuilder();
string clznam = t.Name + "Wrapper";
sb.Append(String.Format(fldtemp, t.Name));
sb.Append(String.Format(contemp, clznam, t.Name));
foreach(PropertyInfo p in t.GetProperties())
{
sb.Append(String.Format(proptemp, p.PropertyType.Name,
p.Name));
sbget.Append(String.Format(lblgettemp, p.Name));
sbset.Append(String.Format(lblsettemp, p.Name));
}
sb.Append(String.Format(methgettemp, sbget.ToString()));
sb.Append(String.Format(methsettemp, sbset.ToString()));
string src = String.Format(nstemp, String.Format(clztemp,
clznam, t.Name, sb.ToString()));
CodeDomProvider comp = new CSharpCodeProvider();
CompilerParameters param = new CompilerParameters();
param.GenerateInMemory = true;
param.ReferencedAssemblies.Add("System.dll");

param.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
CompilerResults res = comp.CompileAssemblyFromSource(param,
src);
if(res.Errors.Count > 0)
{
Console.WriteLine(src);
foreach(CompilerError ce in res.Errors)
{
Console.WriteLine(ce);
}
}
Assembly asm = res.CompiledAssembly;
return asm.GetType("WrapperGen." + clznam);
}
public T Get<T>(T o) where T : class
{
if(!cache.ContainsKey(o.GetType()))
{
cache.Add(o.GetType(), Create(o.GetType()));
}
return (T)cache[o.GetType()].GetConstructor(new Type[] {
o.GetType() }).Invoke(new object[] { o });
}
}
public class Program
{
public static void Main(string[] args)
{
WrapperGen wg = new WrapperGen();
A a = wg.Get(new A());
a.Iv = a.Iv + 1;
a.Sv = "X";
Console.WriteLine(((IWrapper)a).CountGets("Iv") + " " +
((IWrapper)a).CountSets("Iv"));
Console.WriteLine(((IWrapper)a).CountGets("Sv") + " " +
((IWrapper)a).CountSets("Sv"));
B b = wg.Get(new B());
b.Iv = 77;
for(int i = 0; i < 10; i++)
{
int v = b.Iv;
}
Console.WriteLine(((IWrapper)b).CountGets("Iv") + " " +
((IWrapper)b).CountSets("Iv"));
Console.WriteLine(((IWrapper)b).CountGets("Xv") + " " +
((IWrapper)b).CountSets("Xv"));
}
}
}
 
K

kndg

Wow, very cool!
Surely you have a lots under your sleeve.
System.CodeDom.Compiler is not something that people (that's me) will
even to take a look at. Thanks for the idea.
 

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