1

Here is my scenario... I want to have some base class and have some set of extension methods to this class that will be hosted probably in different assemblies. Depending on what assemblies added to the project, different properties should be calculated and stored inside.

I have some base class

public class AObject
{
    public string PropertyA { get; set; }
    public int PropertyB { get; set; }
}

and do have some extension method to this class

public static class AObjectExtensions
{
    public static void DoSomething(this AObject a, string value)
    {
        a.PropertyC = value;
    }
}

What I want to get, I want to do some calculations inside extension method DoSomething and save results as PropertyC inside AObject. AObject doesn't have PropertyC by default, so I want to add it dynamically. I figured out that to work with dynamic properties I have to use ExpandoObject, but not sure that I see how it can be used here...

So, the main question is it a good scenario at all or I have to think about something else?

Mr. Pumpkin
  • 6,212
  • 6
  • 44
  • 60
  • Is it possible that in the situation where you are calling that `DoSomething` that you could guarantee having an object of type `CObject` where that derives from `AObject` and has `PropertyC` on it? It doesn't sound like a good scenario to me and if you could just use derived objects of the right type that would be much more preferable (though of course I have no idea if that is feasible). My thinking though is that if you are in a place where the code knows that `PropertyC` exists it must know enough about the object that you could guarantee it to be a `CObject`... – Chris Jun 11 '15 at 14:41
  • I would like to avoid inheritance... the main idea to have some base object and implement set of extensions that do some work on calculating different types of information related to the object. – Mr. Pumpkin Jun 11 '15 at 14:49
  • Fair enough. As I said I don't know the details of what you are trying to do. If you aren't going to use inheritance then at a glance ExpandoObject would seem your best bet. I note one answer is suggesting DynamicObject which led me to http://stackoverflow.com/questions/3565481/differences-between-expandoobject-dynamicobject-and-dynamic which suggests the expando is simpler and thus if it does the job probably the choice I'd go for. – Chris Jun 11 '15 at 14:56
  • 1
    @Chris: Your link points to task scheduler api. Are you sure that this is the correct one? – Sebastian Schumann Jun 11 '15 at 14:59
  • @Verarind: It wasn't. Hopefully it is now. :) Thanks for pointing that out (and within my edit window too!) – Chris Jun 11 '15 at 15:01
  • I don't quite get your sceneraio. Is there some collaborator in your design that knows all the (dynamic) properties of `AObject`? Or is the `PropertyC` only used in the assembly that also defines it extension-wise? – Good Night Nerd Pride Jun 11 '15 at 15:05

1 Answers1

3

You need to inherit your object from DynamicObject:

public class AObject : DynamicObject
{
    public string PropertyA { get; set; }

    public int PropertyB { get; set; }

    #region Dynamic Part

    private readonly Dictionary<string, object> _members = new Dictionary<string, object>();

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        this._members[binder.Name] = value;
        return true;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        return this._members.TryGetValue(binder.Name, out result) || base.TryGetMember(binder, out result);
    }

    public override IEnumerable<string> GetDynamicMemberNames()
    {
        return this._members.Keys;
    }

    #endregion
}

Your extension method has to be changed to:

public static class AObjectExtensions
{
    public static void DoSomething(this AObject a, string value)
    {
        ((dynamic)a).PropertyC = value;
    }
}

You have the ability to iterate over all dynamic members using GetDynamicMemberNames() and if AObject provides an indexer or a getter method that accesses this._members you can access to all dynamic values.

EDIT: There meight be a problem using this solution. I didn't tested it. ((dynamic)a).PropertyA meight be hidden by Try(Get|Set)Member. If so you can change the getter and setter of PropertyA and ProprertyB to access the _members or you can handle this cases in Try(Get|Set)Member. Adding these properties to _member opens up the possibility to iterate over these members too.

Sebastian Schumann
  • 3,204
  • 19
  • 37