将成员添加到在运行时动态对象

问题描述 投票:26回答:5

我正在探索在.NET 4.0中的DynamicObject模型。该应用程序是一个地方的对象将通过某种文本/ xml文件来描述,程序必须在阅读该文件中创建一个对象。

随着DynamicObject,我们可以假设我们知道该成员的先验的名称很容易添加成员。但是,如果我们甚至不知道添加的成员的名字吗?有没有一种方法,使这种动态呢?

举例来说,假设我需要创建与成员Property1',“Property2”的对象,并用“PropertyA”另一对象,如由文本/ XML文件中描述的“PropertyB”。如何创建动态地根据这个信息的对象?

UPDATE我从这篇文章的一些想法:http://www.codeproject.com/KB/cs/dynamicincsharp.aspx

这种实现允许我这样做如下:

dynamic d = new PFDynamicChannel();
PFCouplings c = ((PFChannel)d).Coupling;
d.NewProperty = "X";

我不希望使用字典的原因是利用TryGetMember,并TrySetMember方法,我可以重写,在其中我可以提高那些对程序必不可少的活动。

这样一来,我可以从一个基类(PFChannel)继承,但我也可以在飞行中添加成员。但是,我的问题是,我不知道新属性的名字,直到运行时。而且,我其实不认为动态对象让我在飞行中增加新的特性。如果是这样的话,我怎么可以利用ExpandoObject的给我这个能力吗?

c# .net dynamic .net-4.0
5个回答
45
投票

如果你只需要做到这一点,你应该看看ExpandoObject。如果你需要做到这一点,仍然使用DynamicObject,你需要编写代码来记住属性值,基本上......你可能带有嵌入式ExpandoObject做。

这不是很清楚,我要与这个对象做以后,虽然什么 - 你确定你需要动态类型呢?将一个Dictionary<string, object>实际上是更糟?这要看是怎么回事消费对象后基本。


33
投票

根据这样的:Adding properties and methods to an ExpandoObject, dynamically!

...您可以使用在Expando对象作为你的价值持有人,并将其转换为一个IDictionary <字符串,对象>如果您要添加动态命名属性。

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

这是测试,将打印出“真”在控制台屏幕上。

当然,你的情况,你的潜在对象必须从另一个类继承,这个例子只是给给你一个想法一个潜在的自定义实现。

也许包括你的类实现在Expando对象和重定向调用tryget和tryset到你们班的expando对象的实例?

UPDATE

如果你的基类派生DynamicObject(这意味着你可以覆盖所有TrySet / GET /调用方法),那么,你也可以使用一个字典内。在尝试的get / set覆盖,你会做任何事件激发你想要的,并委托该设置让到内部字典。

要添加一个新的属性(或删除现有的),你可以重写TryInvoke。当评判名字,例如“方法addProperty”,并有一个字串类型的参数,那么你会在你的字典中添加新项与参数的名称。同样,你会动态地定义了“RemoveProperty”等,你甚至都不需要在Expando对象。

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.

    }
}

当然,正如我所说,这将只工作,如果你的基类DynamicObject派生的。


7
投票

我不知道你想在这种情况下使用动态对象。

动态在C#中,您可以做这样的事情:

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

如果您使用的ExpandoObject,您可以:

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

这两个让你使用PROPERTYNAME仿佛它实际上在编译时存在。在你的情况,你不需要在所有使用这个语法,所以我不知道它会给你任何任何好处。相反,为什么不直接使用Dictionary<string, object>和:

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

因为Dictionary<string,object>基本上是在Expando对象是什么 - 但它有一个不同的语法支持。是的,我简化了 - 但如果你不使用这个和其他的代码,或通过结合的/ etc,那么这是基本属实。


1
投票

有关Thanasis IOANNIDIS回答关于变种“如果你的基类派生DynamicObject”,还有一个更简单的方法,只需添加方法方法addProperty在这样的“MyClass的”类:

    class MyClass: MyBaseClass
    {
        Dictionary<string, object> dynamicProperties = new Dictionary<string, object>();

        public void AddProperty(string key, object value){
            dynamicProperties[key] = value;
        }

然后你可以使用

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

你不需要任何覆盖到“TryInvoke”。


0
投票

dynamic类型的属性包basicaly实现。这意味着其键的字典(属性名)和(非类型安全的方式在这里)的对象。荫如果你能direcly访问到这个字典中没有使用,但是你可以用字典自己。

妈的,乔恩斯基特也较快:(

© www.soinside.com 2019 - 2024. All rights reserved.