C# “救救我”;“干的”;输出此.NETXML序列化代码

C# “救救我”;“干的”;输出此.NETXML序列化代码,c#,refactoring,xml-serialization,dry,C#,Refactoring,Xml Serialization,Dry,我有一个基集合类和一个子集合类,它们都是可序列化的。在一次测试中,我发现简单地使用子类的ReadXml方法调用base.ReadXml之后会导致InvalidCastException。首先,这里是类结构: 基类 // Collection of Row objects [Serializable] [XmlRoot("Rows")] public class Rows : IList<Row>, ICollection<Row>, IEnumerable<Row&

我有一个基集合类和一个子集合类,它们都是可序列化的。在一次测试中,我发现简单地使用子类的
ReadXml
方法调用
base.ReadXml
之后会导致
InvalidCastException
。首先,这里是类结构:

基类

// Collection of Row objects
[Serializable]
[XmlRoot("Rows")]
public class Rows : IList<Row>, ICollection<Row>, IEnumerable<Row>,
    IEquatable<Rows>, IXmlSerializable
{
    public Collection<Row> Collection { get; protected set; }

    public void ReadXml(XmlReader reader)
    {
        reader.ReadToFollowing(XmlNodeName);
        do
        {
            using (XmlReader rowReader = reader.ReadSubtree())
            {
                var row = new Row();
                row.ReadXml(rowReader);
                Collection.Add(row);
            }
        } while (reader.ReadToNextSibling(XmlNodeName));
    }
}
// Acts as a collection of SpecificRow objects, which inherit from Row.  Uses the same
// Collection<Row> that Rows defines which is fine since SpecificRow : Row.
[Serializable]
[XmlRoot("MySpecificRowList")]
public class SpecificRows : Rows, IXmlSerializable
{
    public new void ReadXml(XmlReader reader)
    {
        // Trying to just do base.ReadXml(reader) causes a cast exception later
        reader.ReadToFollowing(XmlNodeName);
        do
        {
            using (XmlReader rowReader = reader.ReadSubtree())
            {
                var row = new SpecificRow();
                row.ReadXml(rowReader);
                Collection.Add(row);
            }
        } while (reader.ReadToNextSibling(XmlNodeName));
    }

    public new Row this[int index]
    {
        // The cast in this getter is what causes InvalidCastException if I try
        // to call base.ReadXml from this class's ReadXml
        get { return (Row)Collection[index]; }
        set { Collection[index] = value; }
    }
}

因此,最重要的代码编译和运行时没有异常,但它让我觉得
Rows.ReadXml
SpecificRows.ReadXml
本质上是相同的代码。
XmlNodeName
的值和
new Row()
/
new specific Row()
的值是不同之处。您建议我如何提取这两个版本的
ReadXml
的所有通用功能?仅仅为一个方法创建一些泛型类是愚蠢的吗?很抱歉代码示例太长,我只是想说明我不能简单地调用
base.ReadXml
的原因,因为
SpecificRows

集合只能包含
对象时,为什么要进行强制转换?也许我错过了什么

更新:

Collection[index] as Row;
将绕过异常,但它可能仍然不会产生您想要的结果(即:一个null而不是一行)

更新:

将基础重构为:

    public void ReadXml<T>(XmlReader reader) where T : IRow
    {
        reader.ReadToFollowing(XmlNodeName);
        do
        {
            using (XmlReader rowReader = reader.ReadSubtree())
            {
                var row = default(T);
                row.ReadXml(rowReader);
                Collection.Add(row);
            }
        } while (reader.ReadToNextSibling(XmlNodeName));
    } 
public-void-ReadXml(XmlReader-reader),其中T:IRow
{
reader.ReadToFollowing(XmlNodeName);
做
{
使用(XmlReader rowReader=reader.ReadSubtree())
{
var行=默认值(T);
ReadXml(rowleader);
集合。添加(行);
}
}while(reader.ReadToNextSibling(XmlNodeName));
} 

为您工作?

集合
只能包含
对象时,您为什么要进行强制转换?也许我错过了什么

更新:

Collection[index] as Row;
将绕过异常,但它可能仍然不会产生您想要的结果(即:一个null而不是一行)

更新:

将基础重构为:

    public void ReadXml<T>(XmlReader reader) where T : IRow
    {
        reader.ReadToFollowing(XmlNodeName);
        do
        {
            using (XmlReader rowReader = reader.ReadSubtree())
            {
                var row = default(T);
                row.ReadXml(rowReader);
                Collection.Add(row);
            }
        } while (reader.ReadToNextSibling(XmlNodeName));
    } 
public-void-ReadXml(XmlReader-reader),其中T:IRow
{
reader.ReadToFollowing(XmlNodeName);
做
{
使用(XmlReader rowReader=reader.ReadSubtree())
{
var行=默认值(T);
ReadXml(rowleader);
集合。添加(行);
}
}while(reader.ReadToNextSibling(XmlNodeName));
} 

为你工作?

看起来唯一的区别是这一行:

var row = new Row();
vs


因此,您可以将其提取到一个虚拟函数中,例如,
MakeRow()
,然后
ReadXml()
可以不重复。

看起来唯一的区别是这一行:

var row = new Row();
vs


因此,您可以将其提取到一个虚拟函数中,例如,
MakeRow()
,然后
ReadXml()
可以不重复。

如果您想这样做,您可以

public void ReadXml<T>(XmlReader reader) where T : IRow, new()
{
    reader.ReadToFollowing(XmlNodeName);
    do
    {
        using (XmlReader rowReader = reader.ReadSubtree())
        {
            var row = new T();
            row.ReadXml(rowReader);
            Collection.Add(row);
        }
    } while (reader.ReadToNextSibling(XmlNodeName));
} 
然后在

// Acts as a collection of SpecificRow objects, which inherit from Row.  Uses the same
// Collection<Row> that Rows defines which is fine since SpecificRow : Row.
[Serializable]
[XmlRoot("MySpecificRowList")]
public class SpecificRows : Rows, IXmlSerializable
{
    protected override Row CreateRow()
    {
        return new SpecificRow();
    }   
}
//充当从行继承的SpecificRow对象的集合。使用相同的
//集合,该集合定义了自SpecificRow:Row以来哪些是正确的。
[可序列化]
[XmlRoot(“MySpecificRowList”)]
公共类SpecificRows:行,IXmlSerializable
{
受保护的重写行CreateRow()
{
返回新的SpecificRow();
}   
}
如果
此[]
方法返回
类型,则不需要重写它。基类已经可以这样做了


如果希望
this[]
返回
SpecificRow
,那么在这个派生类中,可以安全地直接强制转换到该行。。。然而。。。为什么使用它的代码需要知道它处理的是什么类型的行?如果有,那么我会尝试对行对象应用“tell-don-ask”,这样行的使用者就不知道它正在与哪种类型的行对话,再次消除了对该方法的需要。

如果要这样做,可以

public void ReadXml<T>(XmlReader reader) where T : IRow, new()
{
    reader.ReadToFollowing(XmlNodeName);
    do
    {
        using (XmlReader rowReader = reader.ReadSubtree())
        {
            var row = new T();
            row.ReadXml(rowReader);
            Collection.Add(row);
        }
    } while (reader.ReadToNextSibling(XmlNodeName));
} 
然后在

// Acts as a collection of SpecificRow objects, which inherit from Row.  Uses the same
// Collection<Row> that Rows defines which is fine since SpecificRow : Row.
[Serializable]
[XmlRoot("MySpecificRowList")]
public class SpecificRows : Rows, IXmlSerializable
{
    protected override Row CreateRow()
    {
        return new SpecificRow();
    }   
}
//充当从行继承的SpecificRow对象的集合。使用相同的
//集合,该集合定义了自SpecificRow:Row以来哪些是正确的。
[可序列化]
[XmlRoot(“MySpecificRowList”)]
公共类SpecificRows:行,IXmlSerializable
{
受保护的重写行CreateRow()
{
返回新的SpecificRow();
}   
}
如果
此[]
方法返回
类型,则不需要重写它。基类已经可以这样做了


如果希望
this[]
返回
SpecificRow
,那么在这个派生类中,可以安全地直接强制转换到该行。。。然而。。。为什么使用它的代码需要知道它处理的是什么类型的行?如果是这样,那么我将尝试对行对象应用“告诉不要问”,这样行的使用者就不知道它正在与哪种类型的行交谈,再次消除了对该方法的需要。

更新了问题
SpecificRows
充当
SpecificRow
对象和
SpecificRow:Row
的集合。是的,我尝试了
作为
运算符,但没有得到InvalidCastException,但是当我得到
null
而不是我所期望的
行时,我仍然得到了一个异常。但是,是的,我已经解决了这个问题--演员阵容不是我要问的问题。我想将工作的
ReadXml
方法重构到它们仍然可以工作的地方,但不要复制太多的代码。哦,我现在明白了,我可能有一个主意可以帮上忙。
default(t)
如果
t
是一个参考类型更新的问题,那么
ReadXml
将返回
null
SpecificRows
充当
SpecificRow
对象和
SpecificRow:Row
的集合。是的,我尝试了
作为
操作符,但没有得到InvalidCastException,但是当我得到
null
而不是我期望的
行时,我仍然得到了一个异常。但是,是的,我已经修复了p