Adding members to a dynamic object at runtime

前端 未结 5 1009
无人共我
无人共我 2020-12-24 11:53

I am exploring the DynamicObject model in .NET 4.0. The application is one where an object will be described through some sort of text/xml file, and the program must create

相关标签:
5条回答
  • 2020-12-24 12:14

    Related to the Thanasis Ioannidis answer regarding a variant "If your base class derives from DynamicObject", there is a simpler way, just add method AddProperty in "MyClass" class like this:

        class MyClass: MyBaseClass
        {
            Dictionary<string, object> dynamicProperties = new Dictionary<string, object>();
    
            public void AddProperty(string key, object value){
                dynamicProperties[key] = value;
            }
    

    Then you can use

    dynamic myObject = new MyClass();
    myObject.AddProperty("DateOfBirth", new DateTime(1980,23,11));
    

    You don't need any override to "TryInvoke".

    0 讨论(0)
  • 2020-12-24 12:19

    I'm not sure you want to use a dynamic object in this case.

    dynamic in c# lets you do things like :

      dynamic something = GetUnknownObject();
      something.aPropertyThatShouldBeThere = true;
    

    If you use an ExpandoObject, you can:

      var exp = GetMyExpandoObject();
      exp.APropertyThatDidntExist = "something";
    

    Both of these let you use the propertyname as if it actually exists at compile time. In your case, you won't need to use this syntax at all, so I'm not sure that it would give you any benefit whatsoever. Instead, why not just use a Dictionary<string, object>, and:

    var props = new Dictionary<string, object>();
       foreach( var someDefinintion in aFile)
       {
          props[ someDefinition.Name] = someDefinition.value;
       }
    

    Because a Dictionary<string,object> is basically what an expando object is - but it has support for a different syntax. Yes, I'm simplifying - but if you're not using this from other code or through binding / etc, then this is basically true.

    0 讨论(0)
  • 2020-12-24 12:20

    If you only need to do that, you should look at ExpandoObject. If you need to do that and still use DynamicObject, you will need to write code to remember property values, basically... which you could potentially do with an embedded ExpandoObject.

    It's not clear to me what you want to do with this object afterwards though - are you sure you need dynamic typing at all? Would a Dictionary<string, object> actually be any worse? It depends what's going to consume the object later basically.

    0 讨论(0)
  • 2020-12-24 12:30

    According to this: Adding properties and methods to an ExpandoObject, dynamically!,

    ... you can use an expando object as your value holder, and cast it to an IDictionary<string, object> when you want to add dynamically named properties.

    Example

    dynamic myobject = new ExpandoObject();
    
    IDictionary<string, object> myUnderlyingObject = myobject;
    
    myUnderlyingObject.Add("IsDynamic", true); // Adding dynamically named property
    
    Console.WriteLine(myobject.IsDynamic); // Accessing the property the usual way
    

    This is tested and will print out "true" on the console screen.

    Of course, in your case, where your underlying object has to inherit from another class, this example is given just to give you an idea for a potential custom implementation.

    Maybe including an expando object in your class implementation and redirecting calls to tryget and tryset to the instance of the expando object in your class?

    UPDATE

    IF your base class derives from DynamicObject (meaning you can override all TrySet/Get/Invoke methods) then, you could also use a dictionary internally. In the try get/set overrides you would do any event firing you want, and delegate the setting getting to the internal dictionary.

    To add a new property (or remove an existing one) you could override TryInvoke. When the mothod name is, for example, "AddProperty" and there is one argument of type string then you would add a new item in your dictionary with the name of the argument. Similarly you would dynamically define a "RemoveProperty" etc. You don't even need an expando object.

    class MyBaseClass: DynamicObject
    {
        // usefull functionality
    }
    
    class MyClass: MyBaseClass
    {
        Dictionary<string, object> dynamicProperties = new Dictionary<string, object>();
    
        override bool TryGetMember(...)
        {
           // read the value of the requested property from the dictionary
           // fire any events and return
        }
    
        override bool TrySetMember(...)
        {
           // set the value of the requested property to the dictionary
           // if the property does not exist,
           // add it to the dictionary (compile time dynamic property naming)
           // fire any events
        }
    
        override bool TryInvoke(...)
        {
           // check what method is requested to be invoked
           // is it "AddProperty"??
           // if yes, check if the first argument is a string
           // if yes, add a new property to the dictionary
           // with the name given in the first argument (runtime dynamic property naming)
           // if there is also a second argument of type object,
           // set the new property's value to that object.
    
           // if the method to be invoked is "RemoveProperty"
           // and the first argument is a string,
           // remove from the Dictionary the property
           // with the name given in the first argument.
    
           // fire any events
        }
    }
    
    // USAGE
    static class Program
    {
        public static void Main()
        {
            dynamic myObject = new MyClass();
    
            myObject.FirstName = "John"; // compile time naming - TrySetMember
            Console.WriteLine(myObject.FirstName); // TryGetMember
    
            myObject.AddProperty("Salary");  // runtime naming (try invoke "AddProperty" with argument "Salary")
            myObject.Salary = 35000m;
            Console.WriteLine(myObject.Salary); // TryGetMember
    
            myObject.AddProperty("DateOfBirth", new DateTime(1980,23,11)); // runtime naming (try invoke "AddProperty" with fisrt argument "DateOfBirth" and second argument the desired value)
            Console.WriteLine(myObject.DateOfBirth); // TryGetMember
    
            myObject.RemoveProperty("FirstName"); // runtime naming (try invoke "RemoveProperty" with argument "FirstName")
    
            Console.WriteLine(myObject.FirstName); // Should print out empty string (or throw, depending on the desired bahavior) because the "FirstName" property has been removed from the internal dictionary.
    
        }
    }
    

    Of course, as I said, that would work only if your base class Derives from DynamicObject.

    0 讨论(0)
  • 2020-12-24 12:35

    dynamic type is basicaly implemented as Property Bag. That means its dictionary of Keys (property names) and objects (here in non-type-safe way). Iam not use if you can access direcly into this dictionary, but you can use dictionary by yourself.

    Damn, Jon Skeet was faster :(

    0 讨论(0)
提交回复
热议问题