tags:

views:

282

answers:

4

is it possible to easily and dynamically decorate an object?

for example, lets say I have a List<PointF>. this list is actually a plot of the sine function. I'd like to go through these points and add a flag to each PointF of whether it's a peak or not.

but I don't want to create a new extended SpecialPointF or whatever, that has a boolean property.

judge me all you want for being lazy, but laziness is how awesome ideas are born (also bad ideas)

Edit: I'll accept boxing solutions as well as any interesting hack you can come up with. there's nothing really stopping me from deriving. I just want to know if there's a more fun way.

+5  A: 

No, there's no way to do (specifically) what you're asking for.

Assuming you're using C# 3.0+, you can use anonymous types to do this, assuming that you don't want to expose the information outside of your function.

var decoratedList = sourceList.Select(pt => new 
                    { 
                        IsPeak = GetIsPeak(pt), 
                        Point = pt 
                    }).ToList();

This will give you a new List<T> object. This may very well not solve your problem, since you cannot extend this outside of a single function call and you're creating a new list rather than modifying an existing one, but hopefully this helps.

Adam Robinson
That's a cool idea. I haven't used anonymous types yet, so I didnt even think about it.we're pretty cool with using the latest c#, so its not a problem.
Oren Mazor
@Oren: They're nice, but the biggest caveat is not being able to expose them outside of your function. If you needed to do that, you'd have to create your own simple wrapper class with a similar signature, then just say `new WrapperClass { ...` rather than just `new { ...`
Adam Robinson
+1  A: 

No it's not possible.

Closest will be just creating a

var decorationData = new Dictionary <Object, bool>

and then saving your values in there. No need to extend the type directly. You can even use an extension method to access the stored data which will then look like it is a direct property of the object.

public static class PointFPeakExtensions
{ 
    private static var decorationData = new Dictionary <PointF, bool>

    public static bool IsPeak (this PointF point) 
    { 
        return decorationData[point];
    } 
    public static void SetPeak (this PointF point, bool isPeak) 
    { 
        decorationData[point] = isPeak;
    } 
} 

And adding to your edit:

You could also solve this with a generic type that contains just the decoration data and the referenced type (In the same way as Nullable types are implemented in the class libraries). However that still means you have to change the signatures at the places you use the type (which is likely not what you want to do when looking for decorator).

Foxfire
+3  A: 

If there's a way you can calculate that per point, you don't need to add a flag to it, you can use an extension method without having to extend it.

Something like PointF.isPeak();

It works something like:

public static class Extensions
{
    public static bool isPeak (this PointF p)
    {
        do crazy math...

        return result;
    }
}

And voilà, you have your calculation in your PointF class.

By the way, the public static class has to be in the outermost scope, cant be nested.

Francisco Soto
+1. Excellent suggestion, though `isPeak` is not named consistent with .NET naming conventions (first character should be capitalized)
Adam Robinson
That's a fantastic idea. I love it.
Oren Mazor
@Francisco: Extension method is a great idea, but in this case how will a point know if its the peak in a series that it does not contain? Unless the point contains a pointer to the series it's part of...
Partha Choudhury
@Partha I'll be passing the previous and next point to IsPeak, I guess.I'm sure I could do more math juggling and find the peaks using calculus, but that's kind of like the whole "I know! I'll use regular expressions to solve this!" situation :)
Oren Mazor
@Partha: It can't ("do crazy math" is impossible without knowing the series). But you could use a similar method. See my answer to this question.
Foxfire
for the sake of interest, here's what I did:`public static bool IsPeakPoint(this double current, List<double> surroundingPoints){ return surroundingPoints.Max() == current;}`same thing for troughs, but with a Min thrown in there. seems to work quite nicely and I learned something new. I wish I could +1 you again.
Oren Mazor
@Oren, @Francisco, @Foxfire - nice teamwork :-)
Partha Choudhury
+2  A: 

It might be possible to do this using the new dynamic keyword and ExpandoObject construct in C# 4.0, but I don't have firsthand experience with it yet. As I understand it was created to solve this exact problem easily, so you can say

dynamic something = new ExpandoObject();
something.Anything = "whatever you want";

I believe it is possible to extend existing types dynamically, but it might require creating a new subclass, which would defeat the whole purpose of the exercise.

An almost-identical solution can be created using extension methods. The ExpandoObject is internally implemented as a Dictionary, but it adds the classy native syntax.

class Program {

   static void Main(string[] args)
   {
      PointF p = new PointF(0, 0);

      p.SetFlag(true);

      if (p.GetFlag())
         Console.WriteLine("win");
   }

}

public static class Extensions
{
   private static Dictionary<PointF, bool> flags = new Dictionary<PointF, bool>();
   public static bool GetFlag(this PointF key)
   {
      return flags[key];
      //OR return flags.ContainsKey(key) ? flags[key] : false;
   }

   public static void SetFlag(this PointF key, bool val)
   {
      flags[key] = val;
   }
}
Ian Henry
instead of p.SetFlag do you mean to call Extensions.SetFlag(p, true); ?
SB
No, extension methods allow you to make calls that look "native" like that. It automatically calls `Extensions.SetFlag(p, true)` for you.
Ian Henry