【问题标题】:C#: How to remove all null properties from a generic object using reflection?C#:如何使用反射从通用对象中删除所有空属性?
【发布时间】:2009-05-03 19:35:31
【问题描述】:

我想删除通用对象中的所有空属性。它不一定是递归的,一层也可以。

我需要一个用于 JSON 序列化的自定义 JavascriptConvertor 实现的原因是:{"Name":"Aleem", "Age":null, "Type":"Employee"}

我想跳过空对象。

这个任务的函数接受对象并返回一个字典:

IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)

所以我想从 obj 中删除所有 null 属性。所有属性都有getter,但如果没有设置属性,getter会返回null

【问题讨论】:

  • 如何删除成员?这个问题有点不清楚......
  • IIRC,“成员”也是属性和方法。所以我也不知道你会如何“删除”它们。
  • 如果它们为空,那么就没有太多需要删除的东西了吗?
  • 新 { Foo = "lol", Bar = null } 到新 { Foo = "lol" }?除非您在内存中创建自己的类型,否则不要认为这是可能的。匿名(通用?)类型是编译器的错觉,它在编译时创建类型......
  • 嗯,方法不能为空。属性本身没有值(在字段的意义上),因此您必须调用 get 访问器来获取值。如果属性没有 get 访问器怎么办? aleemb 绝对需要解释更多才能让他的问题有意义。

标签: c# reflection


【解决方案1】:

您可以实现自己的JavaScriptConverter 来处理您的类型的序列化。然后,您可以完全控制属性的序列化方式。

@Richards 回答提供了一个很好的 Serialize 方法实现。

Deserialize 方法将非常相似,但我会将实现留给您。现在 JavaScriptConverter 的唯一缺点是它必须从某个地方获取支持的类型。要么像这样硬编码:

public override IEnumerable<Type> SupportedTypes
{ 
    get
    {
        var list = new List<Type>{ typeof(Foo), typeof(Bar)...};
        return list.AsReadOnly();
    }
}

...或使其可配置,例如通过类构造函数。

【讨论】:

  • 彼得,这是一个自定义的 JavascriptConvertor
  • 没错。如果标准转换器包含为 null 的属性,您可以创建自己的转换器来忽略这些属性并将其注册到序列化程序。
  • 他是对的,但是您需要将对象转换为您的类型 Serialize(object obj,... MyObject o = (MyObject)obj; 然后检查属性是否为 null 添加到字典以进行序列化...
  • 对象可以是任何类型:Foo、Bar 等。它可以有任意数量的属性...我想要一个通用的解决方案,而不是单独处理每个对象类型。
【解决方案2】:

以下内容可能会奏效:

public IDictionary<string, object> GetNonNullProertyValues(object obj)
{
    var dictionary = new Dictionary<string, object>();

    foreach (var property in obj.GetType().GetProperties())
    {
        var propertyValue = property.GetValue(obj, null);
        if (propertyValue != null)
        {
            dictionary.Add(property.Name, propertyValue);
        }
    }

    return dictionary;
}

注意:此方法不处理索引属性。

【讨论】:

    【解决方案3】:
     using System.IO;
     using System.Runtime.Serialization.Json;
    
        public static class JsonExtensions
        {
            public static string ToJson<T>(this T instance) 
            {
                var serializer = new DataContractJsonSerializer(typeof(T));
                using (MemoryStream memoryStream = new MemoryStream())
                {
                    serializer.WriteObject(memoryStream, instance);
    
                    memoryStream.Flush();
                    memoryStream.Position = 0;
    
                    using (var reader = new StreamReader(memoryStream))
                    {
                        return reader.ReadToEnd();
                    }
                }
            }
    
            public static T FromJson<T>(this string serialized) 
            {
                var serializer = new DataContractJsonSerializer(typeof(T));
                using (MemoryStream memoryStream = new MemoryStream())
                {
                    using (StreamWriter writer = new StreamWriter(memoryStream))
                    {
                        writer.Write(serialized);
                        writer.Flush();
    
                        memoryStream.Position = 0;
    
                        return (T)serializer.ReadObject(memoryStream);
                    }
                }
            }
        }
    

    【讨论】:

    • 获取 System.Runtime.Serialization.Json 需要参考什么?
    • System.ServiceModel.Web 和 System.Runtime.Serialization
    【解决方案4】:

    您可能希望创建某种包装对象,如果它们不为空,则仅公开其包装的成员。

    您可能还想查看 C# 版本 4。来自the wikipedia entry for duck typing

    C# 版本 4 版本有额外的 类型注释指示 编译器安排类型检查 在运行时发生的类而不是 比编译时间,包括 运行时类型检查代码 编译输出。这样的添加允许 最能享受的语言 用唯一的鸭子打字的好处 缺点是需要识别 并在以下位置指定此类动态类 编译时间。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-01
      • 2011-02-24
      • 1970-01-01
      • 2018-07-01
      • 2015-02-09
      • 1970-01-01
      相关资源
      最近更新 更多