首页 > 解决方案 > 如何更改此代码以允许抽象类或接口在相同的自动生成的类上工作?

问题描述

解释

我使用该xsd.exe工具生成一个基于 XSD(定义 XML 文件的模式)的类 API,从中与 XML 文件进行交互。

这个工具运行良好,但这个问题是我有一些模式与小调整大体上相同,所以我想创建接口或抽象类,允许我在其他地方重用代码。

在下面的示例中,我简化了生成的代码,以便在此处共享,但原则仍然适用。

示例无效代​​码

程序.cs

public static void Main()
{
    BaseColor baseColor = new Color1 { ColorDescription = "Red" };
    BaseShape baseShape = new Shape1 { Content = baseColor };
}

模型.cs

//Auto generated models - I have no control over these but they are partial classes

//First set of autogenerated models, normally in its own file
public partial class Shape1
{
    public Color1 Content { get; set; }
}

public partial class Color1
{

    public string ColorDescription { get; set; }
}

//Second set of autogenerated models, normally in its own file
public partial class Shape2
{
    public Color2 Content { get; set; }
}

public partial class Color2
{

    public string ColorDescription { get; set; }
}

//Attemping to abstract these classes so I can generically use them regardless of underlying type
public abstract class BaseShape
{
    public abstract BaseColor Content { get; set; }
}

public abstract class BaseColor
{
    public abstract string ColorDescription { get; set; }
}

//Attempting to extend the autogenerated classes with the abstract classes
public partial class Shape1 : BaseShape { }

public partial class Color1 : BaseColor { }

public partial class Shape2 : BaseShape { }

public partial class Color2 : BaseColor { }

错误

对于两种形状、两种颜色和两种获取/设置方法,此错误总共重复 8 次。

'Shape1' does not implement inherited abstract member 'BaseShape.Content.set'   XmlSerializeChild

并从Main方法上。

Cannot implicitly convert type 'XmlSerializeChild.Models.BaseColor' to 'XmlSerializeChild.Models.Color1'. An explicit conversion exists (are you missing a cast?)

标签: c#oopinheritanceinterfaceabstract-class

解决方案


您非常接近,但正如 TheGeneral 在他的评论中所写,您无法在覆盖时更改属性的类型。

您可以做的是引入将在代码中使用的新属性(我选择使用接口,但它也可以与抽象类一起使用),并在每个部分类中进行显式转换:

所以首先,我创建了接口:

public interface IColor { string ColorDescription { get; set; } }

public interface IShape { IColor BaseContent { get; set; } }

然后,将IColor实现添加到Color1Color2类中:

public partial class Color1 : IColor {}
public partial class Color2 : IColor {}

(这是简单的部分,因为 ColorDescription 是两种颜色的相同类型)。

接下来,我将IShape实现添加到Shape1andShape2类中:

public partial class Shape1 : IShape 
{
    public IColor BaseContent
    {
        get { return Content; }
        set { Content = (Color1) value; }
    }
}

public partial class Shape2 : IShape 
{
    public IColor BaseContent
    {
        get { return Content; }
        set { Content = (Color2) value; }
    }
}

现在,在该Main方法中,您可以这样做:

var baseColor = new Color1() { ColorDescription = "Red" };
var baseShape = new Shape1() { BaseContent = baseColor };

替代引入新属性的另一种选择IShape是隐式实现接口 - 但这会更麻烦并且不允许您使用new Shape1() {Content = baseColor}语法。不过,让我们也回顾一下这个选项:

所以我们重命名界面BaseContent中的属性:IShape

interface IShape { IColor Content { get; set; } }

我们像这样实现它:

public partial class Shape1 : IShape 
{
    IColor IShape.Content 
    {
        get { return ((Shape1)this).Content; }
        set { ((Shape1)this).Content = (Color1) value; }
    }
}

public partial class Shape2 : IShape 
{
    IColor IShape.Content 
    {
        get { return ((Shape2)this).Content; }
        set { ((Shape2)this).Content = (Color2) value; }
    }
}

然后,我们像这样创建我们的崇敬:

var baseColor = new Color1() { ColorDescription = "Red" };
// Note: Do not use var here - you need the reference to be of type `IShape`!
IShape baseShape = new Shape1();
baseShape.Content = baseColor;

推荐阅读