是否可以在基类中标记一个属性,该属性在子类中仍然有效?
问题可能对序列化非常具体,但我绝对认为还可以有其他用途。
请考虑以下代码:
using System;
using System.IO;
using System.Xml.Serialization;
namespace Code.Without.IDE
{
[Serializable]
public abstract class C1
{
[XmlIgnore]
public abstract bool IsValid_C1 { get; set;}
}
[Serializable]
public class C2 : C1
{
public bool IsValid_C2 { get; set; }
public override bool IsValid_C1 { get; set;}
public C2()
{
IsValid_C1 = true;
IsValid_C2 = false;
}
}
public static class AbstractPropertiesAttributeTest
{
public static void Main(string[] args)
{
C2 c2 = new C2();
using(MemoryStream ms = new MemoryStream())
{
XmlSerializer ser = new XmlSerializer(typeof(C2));
ser.Serialize(ms, c2);
string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine(result);
}
}
}
}
以上代码返回:
------ C:\abhi\Code\CSharp\without IDE\AbstractPropertiesAttributeTest.exe
<?xml version="1.0"?>
<C2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<IsValid_C2>false</IsValid_C2>
<IsValid_C1>true</IsValid_C1>
</C2>
------ Process returned 0
我认为IsValid_C1
会被忽略,但事实并非如此。除了将财产标记为受保护之外,有没有办法实现这一目标?
编辑:一个快速代码,用于显示正在继承XmlIgnore
属性。
http://ideone.com/HH41TE
答案 0 :(得分:1)
我不相信有一种方法可以继承该属性,因为您覆盖了基类属性。你需要用XmlIgnore来装饰C2的IsValid_C1:
[Serializable]
public class C2 : C1
{
public bool IsValid_C2 { get; set; }
[XmlIgnore]
public override bool IsValid_C1 { get; set; }
public C2()
{
IsValid_C1 = true;
IsValid_C2 = false;
}
}
答案 1 :(得分:1)
我将对这个问题提出不同的看法。也许你只是使用这些属性作为一个例子,并希望有几个属性可以级联。但我认为这可能是思考提出的继承模型的好时机。
基本上你可以使用常规继承或者考虑一些设计模式,这不仅可以解决与序列化相关的问题,而且可以在你的应用程序中为你提供更多的“松散耦合”,使其成为更多的组件模型和允许每个班级只处理所关注的问题,这样你就可以重复使用大量的东西,让你的生活更轻松。
基于这种想法,我将为您提供与策略设计模式混合的装饰器设计模式的示例。如果我正在开发类似你样本中的类,那么我就是这样做的:
/// <summary>
/// The interface for validation strategy (since we are using interface, there is no need for another abstract class)
/// </summary>
public interface IValidation
{
bool IsValid { get; set; }
}
/// <summary>
/// The decorator (it dont need to be abstract) that has the serializable properties
/// </summary>
[Serializable]
public class ValidatableDecorator : IValidation
{
protected IValidation instance;
public ValidatableDecorator()
{
Init();
}
public ValidatableDecorator(IValidation instance)
{
Init();
}
protected virtual void Init() { }
public void Set(IValidation instance)
{
this.instance = instance;
}
[XmlIgnore]
public bool IsValid
{
get
{
return instance.IsValid;
}
set
{
instance.IsValid = value;
}
}
}
然后你需要实现一些具有策略模式逻辑的类,如下所示:
public class BossValidatorImplementation : IValidation
{
public bool IsValid
{
get
{
return false; ;
}
set
{
throw new InvalidOperationException("I dont allow you to tell me this!");
}
}
}
public class EasyGoingValidator : IValidation
{
public bool IsValid { get; set; }
}
现在我们已经将逻辑与类分开了,我们可以继承装饰器,选择他们用于IsValid字段的策略,如下所示:
public class ChildWithBossValidation : ValidatableDecorator
{
protected ChildWithBossValidation(IValidation instance)
: this()
{
Init();
}
public ChildWithBossValidation()
: base(new BossValidatorImplementation())
{
Init();
}
protected override void Init()
{
Name = "I'm the boss!";
Sallary = 10000d;
}
public string Name { get; set; }
public double Sallary { get; set; }
}
public class ChildWithEasyGoingValidation : ValidatableDecorator
{
public ChildWithEasyGoingValidation()
: base(new EasyGoingValidator())
{
}
protected ChildWithEasyGoingValidation(IValidation instance)
: this()
{
}
protected override void Init()
{
Name = "Do as you please... :) ";
}
public string Name { get; set; }
}
这是显示解决方案有效的代码:
public static void Main(string[] args)
{
var boos = new ChildWithBossValidation();
var coolGuy = new ChildWithEasyGoingValidation();
using (var ms = new MemoryStream())
{
var ser = new XmlSerializer(boos.GetType());
ser.Serialize(ms, boos);
string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine("With override");
Console.WriteLine(result);
}
Console.WriteLine("-------------");
using (var ms = new MemoryStream())
{
var ser = new XmlSerializer(coolGuy.GetType());
ser.Serialize(ms, coolGuy);
string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine("With override");
Console.WriteLine(result);
}
Console.ReadKey();
}
结果是:
{<?xml version="1.0"?>
<ChildWithBossValidation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>I'm the boss!</Name>
<Sallary>10000</Sallary>
</ChildWithBossValidation>-------------------<?xml version="1.0"?>
<ChildWithEasyGoingValidation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Do as you please... :) </Name>
</ChildWithEasyGoingValidation>}
所以,在这种情况下,也许这并没有回答如何级联属性(因为您可以通过创建自己的属性(标记为允许继承)然后将一些代码实现到SerializeXML来轻松实现)。这只是另一种可以使用Design Pattern改进解决方案整体架构的选项。但这也解决了这个特殊问题:)
答案 2 :(得分:1)
使用类XmlAttributeOverrides和XmlAttributes可以实现所需的行为。我已经为XmlSerializer创建了帮助方法:
public static XmlSerializer GetXmlSerializerWithXmlIgnoreFields(Type t)
{
XmlAttributeOverrides xmlOverrides = new XmlAttributeOverrides();
foreach (var prop in t.GetProperties(BindingFlags.Public|BindingFlags.Instance))
{
Attribute xmlIgnoreAttribute = Attribute.GetCustomAttribute(prop, typeof(XmlIgnoreAttribute));
if (xmlIgnoreAttribute == null)
continue;
XmlAttributes xmlAttributes = new XmlAttributes();
xmlAttributes.XmlIgnore = true;
xmlOverrides.Add(t, prop.Name, xmlAttributes);
}
return new XmlSerializer(t, xmlOverrides);
}
主要方法成为:
public static void Main(string[] args)
{
C2 c2 = new C2();
using (MemoryStream ms = new MemoryStream())
{
XmlSerializer ser = GetXmlSerializerWithXmlIgnoreFields(typeof(C2));
ser.Serialize(ms, c2);
string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine(result);
}
}
答案 3 :(得分:0)
看来这个功能在C#中被破坏了。
您可以编写一个属性,通过反射将为您降低属性。如果你理解反思,那就非常直截了当。