Подтвердить что ты не робот

Список нескольких типов данных?

У меня есть два класса:

public class MachineLine
{
    public double X1;
    public double Y1;
    public double X2;
    public double Y2;
    public double Thickness;
}

public class MachineCircle
{
    public double CenterX;
    public double CenterY;
    public double Radius;
}

Я хочу создать список, который может содержать оба эти файла, но я не хочу, чтобы мой список мог хранить любой другой тип данных. Как это можно сделать?

4b9b3361

Ответ 1

Самый простой способ сделать это - объявить интерфейс и реализовать оба его типа:

public interface IMachine { … }

public class MachineLine : IMachine
{
    public double X1;
    public double Y1;
    public double X2;
    public double Y2;
    public double Thickness;
}

public class MachineCircle : IMachine
{
    public double CenterX;
    public double CenterY;
    public double Radius;
}

Затем вы можете сделать это:

List<IMachine> m = new List<IMachine>();

Ответ 2

У вас есть ответы, объясняющие, как это сделать с пустым интерфейсом:

interface IMachineSomething {}
…
var m = new List<IMachineSomething>();

Это прекрасно работает, если вы хотите поместить объекты в этот список. Но что, если вы хотите на самом деле извлечь объекты из списка? Что вы на самом деле могли бы с ними сделать, и какое решение заставит вас сделать это?

Ниже показано, что вы можете сделать еще лучше с непустым интерфейсом.

IMachineSomething - пустой интерфейс. То есть, если вы действительно хотите что-то сделать с объектами в своем списке, все, что вы увидите, это пустой контракт, определенный этим интерфейсом. Все фактические функциональные возможности соответствуют конкретным типам class. Поэтому вам сначала нужно проверить их тип, а затем выполнить литье типов для доступа к общедоступным полям:

foreach (IMachineSomething sth in m)
{
    if (sth is MachineLine)
    {
        var machineLine = (MachineLine)sth;
        machineLine.DoThis();
    }
    else if (sth is MachineCircle)
    {
        var machineCircle = (MachineCircle)sth;
        machineCircle.DoThat();
    }
    else …
}

Поскольку вы работаете с объектно-ориентированным языком, существует гораздо лучшее решение: полиморфизм. То есть, поместите общую функциональность (свойства, а также методы) в интерфейс, так что вам не нужно будет различать типы при просмотре списка:

interface IMachineSomething
{
    void DoSomething();
}

class MachineLine : IMachineSomething
{
    …
    public void DoSomething() { DoThis(); } // example for implicit implementation, or…
}

class MachineCircle : IMachineSomething
{
    …
    void IMachineSomething.DoSomething() { DoThat(); } // …explicit implementation
}

Это позволяет вам избавиться от проверок типа if (sth is …) и последующих типов, а также упростить код:

foreach (IMachineSomething sth in m)
{
    sth.DoSomething();
}

В цикле больше не нужно заботиться о том, как точно обрабатывается каждый элемент. Все, что нужно знать, должно "что-то делать" с элементом, и сам элемент будет знать, что это значит.

См. также:

Ответ 3

Просто создайте свой собственный интерфейс

public interface IMySillyInterface {}

public class MachineLine : IMySillyInterface
{
    public double X1;
    public double Y1;
    public double X2;
    public double Y2;
    public double Thickness;
}

public class MachineCircle : IMySillyInterface
{
    public double CenterX;
    public double CenterY;
    public double Radius;
}

List<IMySillyInterface> list = new List<IMySillyInterface> 
                                {
                                    new MachineCircle(), 
                                    new MachineLine()
                                };

Ответ 4

У вас есть 2 способа:

1- Использовать наследование:

public class MachineShape{}

public class MachineLine :MachineShape
{
    public double X1;
    public double Y1;
    public double X2;
    public double Y2;
    public double Thickness;
}

public class MachineCircle : MachineShape
{
    public double CenterX;
    public double CenterY;
    public double Radius;
}

List<MachineShape> m = new List<MachineShape>();


2- Использовать интерфейс:

public interface IMachineShape{}

public class MachineLine : IMachineShape
{
    public double X1;
    public double Y1;
    public double X2;
    public double Y2;
    public double Thickness;
}

public class MachineCircle : IMachineShape
{
    public double CenterX;
    public double CenterY;
    public double Radius;
}

List<IMachineShape> m = new List<IMachineShape>();

И я рекомендую наследование в вашем случае...

Ответ 5

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

Ответ 6

Теперь, с С# 7.0 так же просто, как с помощью Tuple:

public List<(MachineLine line, MachineCircle circle)> machineList { get; set; }

Чтобы добавить данные:

MachineLine theLine = ...;
MachineCircle theCircle = ...;

machineList.Add(theLine, theCircle);

Получить данные:

MachineLine ml = emailSender.ElementAt(3).line;
MachineCircle mc = emailSender.ElementAt(3).circle;

Проще, как один, два, три!