1

StepクラスとクラスAutoStepがあります

class Step {
    int StepNumber;
}

class AutoStep {
    int StepNumber;
}

それらはどのクラスからも継承されず、どのクラスからも継承できませ

StepNumberで並べ替え、type(StepまたはAutoStep)に応じて特定のメソッドを呼び出す必要があります

どうやってやるの?

4

6 に答える 6

5

これは文字通り、インターフェイスが作成されたものです。

public interface ISteppable
{
    public int StepNumber { get; }
    public void Foo();//the method you need to call; adjust the signature as needed
}

class step : ISteppable
{
    int StepNumber;

    int ISteppable.StepNumber
    {
        get { return StepNumber; }
    }

    public void Foo()
    {

    }
}

class AutoStep
{
    int StepNumber;

    int ISteppable.StepNumber
    {
        get { return StepNumber; }
    }

    public void Foo()
    {

    }
}

次に、オブジェクトのコレクションを作成し、ISteppableそれらのプロパティを使用してそれらを並べ替え、それぞれをStepNumber呼び出すFooことができます。

どちらのクラスも変更できないため、アダプター パターンを使用して、これらの型のこれらのインターフェイスの実装を作成する必要があります。

public class StepAdapter : ISteppable
{
    private step value;
    public StepAdapter(step value)
    {
        this.value = value;
    }

    public int StepNumber
    {
        get { return value.StepNumber; }
    }

    public void Foo()
    {
        value.Foo();
    }
}

public class AutoStepAdapter : ISteppable
{
    private AutoStep value;
    public AutoStepAdapter(AutoStep value)
    {
        this.value = value;
    }

    public int StepNumber
    {
        get { return value.StepNumber; }
    }

    public void Foo()
    {
        value.Foo();
    }
}

次に、オブジェクトのコレクションを作成できます。オブジェクトISteppableを追加する場合は、stepオブジェクトを でラップし、StepAdapterすべてのAutoStepオブジェクトをAutoStepAdapterオブジェクトでラップします。

List<ISteppable> list = new List<ISteppable>();

list.Add(new StepAdapter(new step(){StepNumber = 5}));
list.Add(new AutoStepAdapter(new AutoStep(){StepNumber = 3}));

list.Sort((a, b) => a.StepNumber.CompareTo(b.StepNumber));

foreach (var item in list)
{
    item.Foo();
}
于 2013-01-08T15:09:02.890 に答える
3

asそれらをキャストするために使用できます:

Step stepObject = input as Step;

if(stepObject != null)
{
  // do something with Step
}

AutoStep autoStepObject = input as AutoStep;

if(autoStepObject != null)
{
  // do something with AutoStep
}
于 2013-01-08T15:02:59.590 に答える
1

同じように扱いたい 2 つの型がある場合は、何らかの形でそれらに対して 1 つの型を作成する必要があります。

この場合の最良のオプションは、共通のインターフェイス (または、おそらく共通の基本クラス) ですが、それは選択肢ではないようです。

もう 1 つの方法は、インターフェイスと、それを継承する 2 つのアダプター (元の型ごとに 1 つ) を作成することです。

どちらのオプションも、Servy's answerで詳しく説明されています。

しかし、さらに別のオプションは、を使用することdynamicです。そのため、同じ名前のプロパティがあれば、同じように使用できます。ただし、(コンパイル時の) タイプ セーフが損なわれるため、このアプローチはお勧めしません。

例(Servyの回答から変更されたコードを使用):

List<dynamic> list = new List<dynamic>();

list.Add(new step{ StepNumber = 5 });
list.Add(new AutoStep{ StepNumber = 3 });

foreach (var item in list.OrderBy(x => x.StepNumber))
{
    item.Foo();
}
于 2013-01-08T15:27:05.447 に答える
0

次の 2 つのリストを定義したとします。

List<AutoStep> autoStepList;
List<Step> stepList;

あなたのクラスの定義によると、フィールドStepNumberは非公開なので、 を通じてアクセスする必要がありますReflection

次のクラスをプロジェクトに追加できます。

using System.Collections.Generic;
using System.Reflection;
using System.Linq;

public partial class AnyStepComparer<T>: IComparer<T> {
    int IComparer<T>.Compare(T stepX, T stepY) {
        if(typeof(Step)==typeof(T)||typeof(AutoStep)==typeof(T))
            return (
                from it in new[] { 0 }
                let type=typeof(T)
                let flagsAccess=BindingFlags.Instance|BindingFlags.NonPublic|BindingFlags.Public
                let invokeAttr=flagsAccess|BindingFlags.GetProperty|BindingFlags.GetField
                let binder=default(Binder)
                let args=default(object[])
                let x=(int)type.InvokeMember("StepNumber", invokeAttr, binder, stepX, args)
                let y=(int)type.InvokeMember("StepNumber", invokeAttr, binder, stepY, args)
                select Comparer<int>.Default.Compare(x, y)
                ).First();

        var message="{0} must be either Step or AutoStep";
        var paramName="[T]";
        throw new ArgumentException(String.Format(message, paramName), paramName);
    }

    public static readonly AnyStepComparer<T> Default=new AnyStepComparer<T>();
}

次に、コードでメソッドを定義します。

public static void SortSteps<T>(List<T> steps) {
    if(steps is List<AutoStep>||steps is List<Step>)
        steps.Sort(AnyStepComparer<T>.Default);
}

次のように呼び出して並べ替えることができます。

SortSteps(autoStepList);

また

SortSteps(stepList);

または、コード内で直接ソートすることもできます:

autoStepList.Sort(AnyStepComparer<AutoStep>.Default);

また

stepList.Sort(AnyStepComparer<Step>.Default);
于 2013-01-08T23:00:58.327 に答える
0

厳密に制約されずに物事を行う方法ではありませんが、次のような並べ替えメソッドを使用できます。

private void sort(object toBeSorted)
{
    if(toBeSorted is Step)
    {
        callStepSort();
    }
    else if(toBeSorted is AutoStep)
    {
        callAutoStepSort();
    }
}

これにより、型のチェックが行われ、継承が回避され、型に関係なく sort メソッドを呼び出すことができます。

しかし、繰り返しになりますが、制約がなければ、これは私がこれを達成する方法ではありません。

于 2013-01-08T16:55:59.957 に答える
0

インターフェイスを使用できる場合、問題はかなり簡単に解決できます。

class step : IStep
{
   ...
   public int StepNumber {get; set;}
}

class AutoStep : IStep
{
   ...
   public int StepNumber {get; set;}
}

interface IStep
{
   public int StepNumber;
}

List<IStep> steps; // list with steps and autosteps
List<IStep> orderedSteps = steps.OrderBy(s => s.StepNumber);
foreach (IStep step in orderedSteps)
{
  if (step is Step)
    // call to method here
  else if (step is AutoStep)
    // call to other method here
}

あるいは、Reflection を使用して何かを行うこともできます (パフォーマンスへの影響があるため、お勧めしません)。

于 2013-01-08T15:14:01.033 に答える