Как мне изменить этот код, чтобы позволить абстрактным классам или интерфейсам работать над идентичными автоматически сгенерированными классами? - PullRequest
0 голосов
/ 08 ноября 2018

Объяснение

Я использую инструмент xsd.exe для генерации API класса на основе XSD (определяет схему для файлов XML), из которого можно взаимодействовать с файлами XML.

Этот инструмент работает хорошо, но проблема в том, что у меня есть несколько схем, которые в целом идентичны с небольшими изменениями, поэтому я хочу создать интерфейсы или абстрактные классы, которые позволят мне повторно использовать код в другом месте.

В моем примере ниже я упростил сгенерированный код, чтобы поделиться им здесь, но принцип все еще остается в силе.

Пример неработающего кода

Program.cs

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

Models.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 раз для обеих фигур, обоих цветов и обоих методов get / set.

'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?)

1 Ответ

0 голосов
/ 08 ноября 2018

Вы довольно близко, но, как пишет TheGeneral в своем комментарии, вы не можете изменить тип свойства при его переопределении.

Что вы можете сделать, это ввести новое свойство (я выбрал использование интерфейсов, но оно будет работать точно так же и с абстрактными классами), которое будет использоваться в коде с явным приведением в каждом частичном классе:

Итак, во-первых, я создал интерфейсы:

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

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

Затем добавили реализацию IColor к классам Color1 и Color2:

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

(Это было легко, так как ColorDescription одинакового типа для обоих цветов).

Затем я добавил реализацию IShape к классам Shape1 и Shape2:

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...