2010-10-14 94 views
22

我正在探索.NET 4.0中的DynamicObject模型。應用程序是通過某種文本/ xml文件描述對象的程序,並且程序必須在讀取該文件時創建對象。在運行時將成員添加到動態對象

使用DynamicObject,我們可以輕鬆地添加成員,因爲我們知道成員的先驗名稱。但是,如果我們甚至不知道要添加的成員的名字呢?有沒有辦法讓這種動態變得更好?例如,假設我需要用文本/ XML文件描述的方式創建一個包含成員'Property1','Property2'和另一個'PropertyA'和'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來給我這個能力?

+2

你還是不明白爲什麼動態和ExpandoObject進入.NET。原因與你想要的完全相反。 ExpandoObject仍然使用Dictionary ,以及它是Dictionary。編譯器僅將所有「屬性」調用轉換爲Dictionary [NameOfProperty]。這使得代碼更好。但這就是它唯一的代碼糖。即使您使用任何動態輸入法,您也可以使用字典進行操作。 – Euphoric 2010-10-14 14:41:03

+0

如何設置字典項目時需要提出的事件? – sbenderli 2010-10-14 14:43:35

+0

[動態添加成員到動態對象](http:// stackoverflow。com/questions/2079870/dynamic-adding-members-to-a-dynamic-object) – nawfal 2014-07-20 07:04:11

回答

37

如果你只有需要這樣做,你應該看看ExpandoObject。如果你需要這樣做仍然使用DynamicObject,你將需要編寫代碼來記住屬性值,基本上......你可能會用嵌入ExpandoObject做這些。

雖然我不清楚你想用這個對象做什麼,但是 - 你確定你需要動態打字嗎? Dictionary<string, object>實際上會更糟嗎?這取決於基本以後會消耗什麼對象。

+0

那麼,對象實際上需要繼承一個基類。基類定義了許多對程序其餘部分都很重要的事件和屬性。我對DynamicObject感興趣的一個原因是我可以重寫TryGetMember和TrySetMember方法,在這些方法中我需要引發事件。但是,如何將一段代碼添加一個名字未知的成員看起來像? – sbenderli 2010-10-14 14:30:29

+0

@sbenderli - 然後,您可以簡單地創建從您的基類派生的新對象,並且此對象可以使用Dictionary 來保留有關「未知」屬性的信息。 – Euphoric 2010-10-14 14:37:01

+0

請參閱我的更新 – sbenderli 2010-10-14 14:37:05

6

我不確定你想在這種情況下使用動態對象。

在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對象是什麼 - 但它有一個不同的語法支持。是的,我正在簡化 - 但如果你沒有使用其他代碼或通過綁定/等,這基本上是真實的。

+0

請參閱我的更新 – sbenderli 2010-10-14 14:36:36

0

dynamic類型基本上是作爲Property Bag實現的。這意味着它的字典Keys(屬性名稱)和對象(在這裏以非類型安全的方式)。如果您可以直接訪問此字典,Iam不會使用,但您可以自行使用字典。

媽,喬恩斯基特也較快:(

25

根據這個: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對象,並將調用重定向到您的類中的expando對象的實例tryget和tryset?

UPDATE

如果你的基類派生DynamicObject(這意味着你可以覆蓋所有TrySet/GET /調用方法),那麼,你也可以使用一個字典內。在嘗試獲取/設置覆蓋時,您可以執行任何需要的事件觸發,並將設置委託給內部字典。

要添加新屬性(或刪除現有屬性),您可以重寫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派生時纔有效。

1

相關的Thanasis IOANNIDIS回答關於變種「如果你的基類DynamicObject派生」,還有一個更簡單的方法,只是在這樣的「MyClass的」類添加方法,方法addProperty:

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」。