簡體   English   中英

在不同的自定義類和集合上的反射GetProperty

[英]Reflection GetProperties on different custom classes and collections

在Web API中,我創建了一個自定義MediaTypeFormatter來創建具有特定架構的JSON輸出,從而使標准序列化不適用。 並非以上上下文可能是相關的,但是我需要轉換一個對象,並且還需要使用指定的架構將IEnumerable轉換為JSON。

用偽代碼:

If object is a collection
  foreach item in collection
     Write the name/type of the item (will be same for all)
         foreach property of item
              Write the property name, type, and value
Else
  foreach property of object 
     Write the property name, type, and value

我最感興趣的部分是通過反射獲取類屬性名稱/值。

例如,這是從控制器發送的:

return new MyPerson { .FirstName = "Bob", .DateOfBirth = Convert.ToDateTime("1979-03-01") }

...將輸出為(粗略的示例,因為JSON易於更改以構建必要的模式):

{ "MyPerson" : {"FirstName": {"value": "Bob", "Type": "string"}}, "DateOfBirth": {"value": "1979-03-01", "Type": "date"}}

同樣,將迭代一個集合以產生類似的輸出:

return new IEnumerable<Foo>() {
    new Foo() { Param1 = "aaa", Param2 = "bbb" },
    new Foo() { Param1 = "ccc", Param2 = "ddd" }
}

...生產

{ "FooCollection": [ 
    { "Foo" : {"Param1": {"value": "aaa", "Type": "string"}}, {"Param2": {"value": "bbb", "Type": "string"}} },
    { "Foo" : {"Param1": {"value": "ccc", "Type": "string"}}, {"Param2": {"value": "ddd", "Type": "string"}} }
]}

我試圖消化許多其他的例子( 12關於這一挑戰),但我在努力適應他們。 據我所設法獲得的:

private void WriteStream(Type type, object value, Stream stream, HttpContentHeaders contentHeaders)
{
    using (StringWriter _stringWriter = new StringWriter()) {
        if (!(value is ICollection))
        {
            foreach (PropertyInfo p in value.GetProperties())
            {
                _stringWriter.Write(GetPropertyData(p));
            }
        }
        else
        {
            foreach (object o in value)
            {
                foreach (PropertyInfo p in o.GetProperties())
                {
                    _stringWriter.Write(GetPropertyData(p));
                }
            }
        }
        // output omitted for brevity...
    }
}

public function GetPropertyData(PropertyInfo p) {
    return string.Format("{name: '{0}', type: '{1}', value: '{2}'},", 
        p.Name, 
        p.PropertyType.ToString(), 
        p.GetValue(p).ToString())
}

我相信您以錯誤的方式來解決您的問題。 不必通過創建自定義MediaTypeFormatter來重新發明輪子,而應該為對象使用正確的模型,讓序列化器完成其余的工作。

一個示例是出於您的目的使用擴展方法:

public static class JsonExtensions
{
    public static object CreateModels<T>(this IEnumerable<T> models, string modelName = null)
    {
        modelName = modelName ?? typeof(T).Name+"Collection";

        return new Dictionary<string, object>()
        {
            { modelName, models.Select(m => CreateModel(m)) }
        };
    }

    public static IDictionary<string, object> CreateModel<T>(this T model, string modelName = null)
    {
        modelName = modelName ?? typeof(T).Name;

        return new Dictionary<string, object>()
        {
            { modelName, GetProperties(model) }
        };
    }

    private static IDictionary<string, object> GetProperties<T>(T obj)
    {
        var props = typeof(T).GetProperties();
        return props.ToDictionary(p => p.Name, p => (object)new { type = p.PropertyType.ToString(), value = p.GetValue(obj, null).ToString() });
    }
}

假設您在項目中使用Json.NET,則使用它們的方式如下:

JsonConvert.SerializeObject(new MyPerson { FirstName = "Bob", DateOfBirth = Convert.ToDateTime("1979-03-01") }.CreateModel());

輸出(漂亮打印):

{
  "MyPerson": {
    "FirstName": {
      "type": "System.String",
      "value": "Bob"
    },
    "DateOfBirth": {
      "type": "System.DateTime",
      "value": "3\/1\/1979 12:00:00 AM"
    }
  }
}

而:

JsonConvert.SerializeObject(new List<Foo>() {
    new Foo() { Param1 = "aaa", Param2 = "bbb" },
    new Foo() { Param1 = "ccc", Param2 = "ddd" }
}.CreateModels());

輸出:

{
  "FooCollection": [
    {
      "Foo": {
        "Param1": {
          "type": "System.String",
          "value": "aaa"
        },
        "Param2": {
          "type": "System.String",
          "value": "bbb"
        }
      }
    },
    {
      "Foo": {
        "Param1": {
          "type": "System.String",
          "value": "ccc"
        },
        "Param2": {
          "type": "System.String",
          "value": "ddd"
        }
      }
    }
  ]
}

.NET小提琴演示這里

注意

我在您的示例中看到,您使用string而不是System.String作為屬性的類型名稱。 使用別名類型名稱而不是CLR真實名稱並不容易,但是如果確實有必要,您可以查看此答案以獲取相關信息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM