web-dev-qa-db-ja.com

複数のデータ型のリスト?

そのような2つのクラスがあります。

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;
}

これらの両方を保持できるリストを作成したいのですが、リストに他のデータ型を保持できないようにします。これをどのように行うことができますか?

46
Adam S

これを行う最も簡単な方法は、インターフェイスを宣言し、両方のタイプに実装させることです。

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>();
59
Dean Chalk

空のインターフェイスでこれを行う方法を説明するいくつかの答えがあります:

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

これは、オブジェクトを配置したいものすべてintoそのリストであればうまく機能します。しかし、実際にオブジェクトを取得したい場合はどうすればいいですか?fromリスト実際にそれらを使って何ができますか?また、上記の解決策は何を強制しますか?

以下は、non-emptyインターフェースを使用するとさらに改善できることを示しています。

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();
}
_

ループでは、各要素が正確に処理される方法を考慮する必要がなくなりました。要素で「何かをする」必要があることを知る必要があり、要素自体はそれが何を意味するかを知っています。

こちらもご覧ください:

35
stakx

次の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>();

そして、あなたの場合は継承をお勧めします...

8
Betamoo

独自のインターフェイスを作成するだけです

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()
                                };
7
Adriaan Stander

2つのクラスに同じインターフェイスを実装させ、そのインターフェイスをListのジェネリック型に含めることができます。

6
BoltClock

さて、C#7.0では、タプルを使用するのと同じくらい簡単です。

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

データを追加するには(((と))、paramsの括弧とTupleを示す別の括弧に注意してください):

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

machineList.Add((theLine, theCircle));

データを取得するには:

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

1、2、3と同じくらい簡単!

2
Adelaiglesia