2014-09-30 52 views
6

我有一个对象,它看起来是这样的(显然简体)如何序列化所有,但一个特定的属性在一个特定的序列化

public class Person { 
    public string Name { get; set; } 
    public int Age { get; set; } 
    public string ETag { get { return ... } } 
} 

我想什么是ETag的是JSON序列化的哈希该对象省略了ETag属性(以防止递归循环)。但是,我不能仅仅使用[JsonIgnore]属性,因为在其他时候我希望能够将json序列化为整个事物。

所以,我想是这样的

public string ETag { get { 
    return Hash(JsonConvert.Serialize(this, p => p.Ignore(x=>x.ETag))); 
}} 

这是不幸的是没有存在的API。我将如何实现类似的东西?

+0

不是最漂亮的解决方案,但我刚刚创建了一个可以从省略领域的主要一个构造相似的对象,序列化,当我需要它。 – BradleyDotNET 2014-09-30 22:24:24

+0

@BradleyDotNET是很多方式来做到这一点与automapper和东西,但它成为一个麻烦,因为我期望这个对象改变很多 – 2014-09-30 22:25:28

回答

5

您可以使用自定义IContractResolver以编程方式忽略对象的属性。所以我认为我会采取的方法是创建一个简单的解析器,可以明确地忽略单个类型的单个属性(显然,如果需要,可以扩展此属性),然后创建一个可以使用该解析器序列化的帮助器方法。使用ETag属性中的帮助器方法,您很好。

下面是解析器代码:

class IgnorePropertyResolver : DefaultContractResolver 
{ 
    Type targetType; 
    string targetPropertyName; 

    public IgnorePropertyResolver(Type targetType, string propertyName) 
    { 
     this.targetType = targetType; 
     this.targetPropertyName = propertyName; 
    } 

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) 
    { 
     IList<JsonProperty> props = base.CreateProperties(type, memberSerialization); 
     if (targetType == type) 
     { 
      props = props.Where(p => p.PropertyName != targetPropertyName).ToList(); 
     } 
     return props; 
    } 
} 

这里的辅助方法(我也是在那里扔,因为你没有在你的问题中定义它哈希helper方法):

static class JsonHelper 
{ 
    public static string Serialize(object target, string propertyToIgnore) 
    { 
     JsonSerializerSettings settings = new JsonSerializerSettings(); 
     settings.ContractResolver = new IgnorePropertyResolver(target.GetType(), propertyToIgnore); 
     return JsonConvert.SerializeObject(target, settings); 
    } 

    public static string Hash(string json) 
    { 
     using (var sha = new SHA1Managed()) 
     { 
      return Convert.ToBase64String(sha.ComputeHash(Encoding.UTF8.GetBytes(json))); 
     } 
    } 
} 

最后,这里的工作演示:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Person p = new Person { Name = "Joe", Age = 26 }; 
     Console.WriteLine("Etag = " + p.ETag); 
     Console.WriteLine(); 
     Console.WriteLine(JsonConvert.SerializeObject(p, Formatting.Indented)); 
    } 
} 

public class Person 
{ 
    public string Name { get; set; } 
    public int Age { get; set; } 
    public string ETag 
    { 
     get { return JsonHelper.Hash(JsonHelper.Serialize(this, "ETag")); } 
    } 
} 

输出:

Etag = T99YVDlrbZ66YL2u5MYjyIyO4Qk= 

{ 
    "Name": "Joe", 
    "Age": 26, 
    "ETag": "T99YVDlrbZ66YL2u5MYjyIyO4Qk=" 
} 

小提琴:https://dotnetfiddle.net/YgVJ4K

+2

如果你想避免字符串类型的属性名称,你可以使用表达式树解析来保持它所有的强类型。我在这里更新了Brian的例子:https://dotnetfiddle.net/G5u8NJ – bitwalker 2014-10-01 00:54:42

+0

@bitwalker很好地完成了。 – 2014-10-01 02:01:19

+0

太好了。非常感谢!我不介意在这种情况下输入字符串,因为在这种情况下,所有属性都被命名为属性实例 – 2014-10-01 02:11:53

0

它并不漂亮,但可以在JSON序列化之后使用字符串替换。您可以将ETag设置为标记值,​​以便在序列化后可以替换/移除该元素。

+0

请给代码?这样做仍然会调用Etag导致递归循环。我知道有更好的方法来处理JsonSerializerSettings,我只是不知道具体如何 – 2014-09-30 22:42:04

相关问题