- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在序列化具有私有(private)属性的派生对象时遇到 Json.Net 问题。像什么
public class Base
{
[JsonProperty]
private string Type { get { return "Base"; } }
}
public class Inherited : Base
{
[JsonProperty]
private string Type { get { return "Inherited"; } }
}
当我序列化 Inherited
的实例时,Type
属性始终设置为“Base”。我发现可行的唯一方法是该属性 protected 或公开并在子类中被覆盖。
为什么会这样?这是一个错误吗?
最佳答案
看起来这是 Json.NET 的预期行为。来自 ReflectionUtils.cs :
private static void GetChildPrivateProperties(IList<PropertyInfo> initialProperties, Type targetType, BindingFlags bindingAttr)
{
// fix weirdness with private PropertyInfos only being returned for the current Type
// find base type properties and add them to result
// also find base properties that have been hidden by subtype properties with the same name
while ((targetType = targetType.BaseType()) != null)
{
foreach (PropertyInfo propertyInfo in targetType.GetProperties(bindingAttr))
{
PropertyInfo subTypeProperty = propertyInfo;
if (!IsPublic(subTypeProperty))
{
// have to test on name rather than reference because instances are different
// depending on the type that GetProperties was called on
int index = initialProperties.IndexOf(p => p.Name == subTypeProperty.Name);
if (index == -1)
{
initialProperties.Add(subTypeProperty);
}
else
{
PropertyInfo childProperty = initialProperties[index];
// don't replace public child with private base
if (!IsPublic(childProperty))
{
// replace nonpublic properties for a child, but gotten from
// the parent with the one from the child
// the property gotten from the child will have access to private getter/setter
initialProperties[index] = subTypeProperty;
}
这是生成类型属性列表的地方,如您所见,有些代码有意优先选择基类中的同名属性而不是继承类中的属性。
我不知道为什么 Json.NET 这样做,你可能想报告一个问题并询问为什么。同时,您可以使用 IContractResolver
有选择地防止这种行为:
[System.AttributeUsage(AttributeTargets.Property)]
public class JsonPreferDerivedPropertyAttribute : System.Attribute
{
}
public class PreferDerivedPropertyContractResolver : DefaultContractResolver
{
static PropertyInfo GetDerivedPropertyRecursive(Type objectType, Type stopType, PropertyInfo property)
{
var parameters = property.GetIndexParameters().Select(info => info.ParameterType).ToArray();
for (; objectType != null && objectType != stopType; objectType = objectType.BaseType)
{
var derivedProperty = objectType.GetProperty(
property.Name,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, property.PropertyType,
parameters,
null);
if (derivedProperty == null)
continue;
if (derivedProperty == property)
return derivedProperty; // No override.
if (derivedProperty.GetCustomAttribute<JsonPreferDerivedPropertyAttribute>() != null)
return derivedProperty;
}
return null;
}
protected override List<MemberInfo> GetSerializableMembers(Type objectType)
{
var list = base.GetSerializableMembers(objectType);
for (int i = 0; i < list.Count; i++)
{
var property = list[i] as PropertyInfo;
if (property == null)
continue;
if (property.DeclaringType != objectType)
{
var derivedProperty = GetDerivedPropertyRecursive(objectType, property.DeclaringType, property);
if (derivedProperty == null || derivedProperty == property)
continue;
if (derivedProperty != property
&& (property.GetGetMethod(true) == null || derivedProperty.GetGetMethod(true) != null)
&& (property.GetSetMethod(true) == null || derivedProperty.GetSetMethod(true) != null))
{
list[i] = derivedProperty;
}
}
}
return list;
}
}
我建议有选择地执行此操作,因为我不完全理解为什么 Json.NET 会这样做。上面的代码仅覆盖了应用了自定义 JsonPreferDerivedPropertyAttribute
属性的派生类属性的默认行为。
然后像这样使用它:
public class Base
{
[JsonProperty]
private string Type { get { return "Base"; } }
}
public class Inherited : Base
{
[JsonProperty]
[JsonPreferDerivedPropertyAttribute]
private string Type { get { return "Inherited"; } }
}
public class VeryInherited : Inherited
{
[JsonProperty]
public string VeryInheritedProperty { get { return "VeryInherited"; } }
}
public static class TestOverride
{
public static void Test()
{
var inherited = new Inherited();
var json1 = JsonConvert.SerializeObject(inherited, Formatting.Indented, new JsonSerializerSettings() { ContractResolver = new PreferDerivedPropertyContractResolver() });
var veryInherited = new VeryInherited();
var json2 = JsonConvert.SerializeObject(veryInherited, Formatting.Indented, new JsonSerializerSettings() { ContractResolver = new PreferDerivedPropertyContractResolver() });
Debug.WriteLine(json1);
Debug.WriteLine(json2);
}
}
输出是:
{
"Type": "Inherited"
}
和
{
"VeryInheritedProperty": "VeryInherited",
"Type": "Inherited"
}
关于c# - JsonPropertyAttribute 在派生类中的私有(private)属性上被忽略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27887787/
你能比较一下属性吗 我想禁用文本框“txtName”。有两种方式 使用javascript,txtName.disabled = true 使用 ASP.NET, 哪种方法更好,为什么? 最佳答案 我
Count 属性 返回一个集合或 Dictionary 对象包含的项目数。只读。 object.Count object 可以是“应用于”列表中列出的任何集合或对
CompareMode 属性 设置并返回在 Dictionary 对象中比较字符串关键字的比较模式。 object.CompareMode[ = compare] 参数
Column 属性 只读属性,返回 TextStream 文件中当前字符位置的列号。 object.Column object 通常是 TextStream 对象的名称。
AvailableSpace 属性 返回指定的驱动器或网络共享对于用户的可用空间大小。 object.AvailableSpace object 应为 Drive 
Attributes 属性 设置或返回文件或文件夹的属性。可读写或只读(与属性有关)。 object.Attributes [= newattributes] 参数 object
AtEndOfStream 属性 如果文件指针位于 TextStream 文件末,则返回 True;否则如果不为只读则返回 False。 object.A
AtEndOfLine 属性 TextStream 文件中,如果文件指针指向行末标记,就返回 True;否则如果不是只读则返回 False。 object.AtEn
RootFolder 属性 返回一个 Folder 对象,表示指定驱动器的根文件夹。只读。 object.RootFolder object 应为 Dr
Path 属性 返回指定文件、文件夹或驱动器的路径。 object.Path object 应为 File、Folder 或 Drive 对象的名称。 说明 对于驱动器,路径不包含根目录。
ParentFolder 属性 返回指定文件或文件夹的父文件夹。只读。 object.ParentFolder object 应为 File 或 Folder 对象的名称。 说明 以下代码
Name 属性 设置或返回指定的文件或文件夹的名称。可读写。 object.Name [= newname] 参数 object 必选项。应为 File 或&
Line 属性 只读属性,返回 TextStream 文件中的当前行号。 object.Line object 通常是 TextStream 对象的名称。 说明 文件刚
Key 属性 在 Dictionary 对象中设置 key。 object.Key(key) = newkey 参数 object 必选项。通常是 Dictionary 
Item 属性 设置或返回 Dictionary 对象中指定的 key 对应的 item,或返回集合中基于指定的 key 的&
IsRootFolder 属性 如果指定的文件夹是根文件夹,返回 True;否则返回 False。 object.IsRootFolder object 应为&n
IsReady 属性 如果指定的驱动器就绪,返回 True;否则返回 False。 object.IsReady object 应为 Drive&nbs
FreeSpace 属性 返回指定的驱动器或网络共享对于用户的可用空间大小。只读。 object.FreeSpace object 应为 Drive 对象的名称。
FileSystem 属性 返回指定的驱动器使用的文件系统的类型。 object.FileSystem object 应为 Drive 对象的名称。 说明 可
Files 属性 返回由指定文件夹中所有 File 对象(包括隐藏文件和系统文件)组成的 Files 集合。 object.Files object&n
我是一名优秀的程序员,十分优秀!