我有一Step堂课和一AutoStep堂课
class Step {
    int StepNumber;
}
class AutoStep {
    int StepNumber;
}
它们不是从任何类继承的,也不能从任何类继承。
我必须按 StepNumber 对它们进行排序并根据它们的类型(Step或AutoStep)调用特定方法
我怎样才能做到这一点?
我有一Step堂课和一AutoStep堂课
class Step {
    int StepNumber;
}
class AutoStep {
    int StepNumber;
}
它们不是从任何类继承的,也不能从任何类继承。
我必须按 StepNumber 对它们进行排序并根据它们的类型(Step或AutoStep)调用特定方法
我怎样才能做到这一点?
从字面上看,这就是接口的用途:
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对象时,只需将它包装在 a 中StepAdapter并将所有AutoStep对象包装在AutoStepAdapterobjects 中。
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();
}
您可以使用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
}
如果您有两种类型要以相同的方式处理,您应该以某种方式为它们创建一个类型。
在这种情况下,最好的选择是通用接口(或者可能是通用基类),但这似乎不是您的选择。
另一种方法是创建接口和从它继承的两个适配器(每个原始类型一个)。
Servy 的回答很好地解释了这两个选项。
但另一种选择是使用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();
}
如果您可以使用接口,则问题很容易解决:
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
}
或者,您也许可以使用反射做一些事情(由于性能影响,不建议这样做)。
这绝对不是我在不受严格限制的情况下做事的方式,但是您可以使用以下排序方法:
private void sort(object toBeSorted)
{
    if(toBeSorted is Step)
    {
        callStepSort();
    }
    else if(toBeSorted is AutoStep)
    {
        callAutoStepSort();
    }
}
这负责检查类型,避免继承,并允许您调用 sort 方法而不管类型如何。
但同样,如果没有限制,这根本不是我要做到这一点的方式。
假设您定义了两个列表:
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);