2013-07-23 88 views
6

有沒有辦法向匿名類添加額外屬性(或者使用額外屬性創建新實例)?爲匿名類添加額外屬性

string cssClasses = "hide"; 
object viewData = new { @class = cssClasses }; 
if (suppliedId != null) 
{ 
    // add an extra id property to the viewData somehow... 
    // desired end result is { @id = suppliedId, @class = cssClasses } 
} 
// ... code will be passing the viewData as the additionalViewData parameter in asp.mvc's .EditorFor method 

回答

1

感謝來自Patryk評論我給它使用ExpandoObject一個去得到它的工作是這樣的:

dynamic viewData = new ExpandoObject(); 
[email protected] = cssClasses; 
if (controlId != null) 
    viewData.id = controlId; 
if (title != null) 
    viewData.title = title; 
// put the result into a route value dictionary so that MVC's EditorFor (etc) can interpret it 
var additionalViewData = new RouteValueDictionary(viewData); 

最後一行的關鍵是得到它在MVC的工作,以便它可以被傳遞作爲EditorFor中的additionalViewData參數。

在我傳遞一個匿名類並需要自己添加它的情況下,我使用反射(並利用ExpandoObject實現IDictionary)。下面是我寫檢查,它的作品的單元測試:

[TestMethod] 
public void ShouldBeAbleToConvertAnAnonymousObjectToAnExpandoObject() 
{ 
    var additionalViewData = new {id = "myControlId", css = "hide well"}; 
    dynamic result = new ExpandoObject(); 
    var dict = (IDictionary<string, object>)result; 
    foreach (PropertyInfo propertyInfo in additionalViewData.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) 
    { 
    dict[propertyInfo.Name] = propertyInfo.GetValue(additionalViewData, null); 
    } 
    Assert.AreEqual(result.id, "myControlId"); 
    Assert.AreEqual(result.css, "hide well"); 
} 
6

不,你不能這樣做。你可以重新定義它,但:

dynamic viewData = new { @class = cssClasses }; 
if (suppliedId != null) 
{ 
    viewData = new { @class = [email protected], yourExtra = Property }; 
} 

注意,我把它改成dynamic。這只是讓您可以編輯屬性而無需投射到dynamic

+3

是的,要麼或使用'dynamic'用'ExpandoObject'代替:) –

+0

@PatrykĆwiek呀,真的。我很喜歡ExpandoObject tbh,這很酷。 –

+0

我不明白你爲什麼不在代碼中保留'object'?這兩種匿名類型都是「對象」。 –

2

您不能爲匿名類型添加額外屬性,但可以使用兩個匿名類型。

如果你不喜歡dynamic(並且有理由不),你可以這樣做:

object viewData; 
if (suppliedId == null) 
    viewData = new { @class = cssClasses, }; 
else 
    viewData = new { @id = suppliedId, @class = cssClasses, }; 

如果你想保持獨立的確切類型引用到每個對象實例,然後使用:

var viewDataSimple = new { @class = cssClasses, }; 
var viewDataExtra = new { @id = suppliedId, @class = cssClasses, }; 
object viewDataToUse; 
if (suppliedId == null) 
    viewDataToUse = viewDataSimple; 
else 
    viewDataToUse = viewDataExtra; 

改爲。

+0

+1是的,這正是我所做的。現在我已經有了一些額外的屬性,所以排列的數量已經失控。 –

+0

@JonathanMoffatt然後,也許你真的想在'System中的'ExpandoObject'類(http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject.aspx)。動態'命名空間。它的作用正好是在您添加新成員時。看到我在那裏給出的鏈接的例子。編輯:啊,剛從你的新答案中看到你已經發現了。 –

0

您可以通過使用反射達到要求,你可以通過鍵值對添加新的屬性。

string cssClasses = "hide"; 
     object viewData = new { @class = cssClasses }; 
     dynamic expandoData = new ExpandoObject(); 
     var processedData = expandoData as IDictionary<String, object>; 
     if (viewData != null) 
     { 
      PropertyInfo[] properties = viewData.GetType().GetProperties(); 
      foreach (var prop in properties) 
      { 
       if (prop == null) continue; 
       object valueObj = viewData .GetType().GetProperty(prop.Name).GetValue(viewData , null); 
       processedData[prop.Name.ToString()] = valueObj; 
      } 
     }   
     processedData["AdditionalPropertyName"] = AdditionalProperty; 
     var infoJson = JsonConvert.SerializeObject(processedData); 
+0

你應該描述你現在提供的解決方案,它只是一個差異 - 不是一個正確的答案 – DomTomCat