如何排序2个不同的列表
本文关键字:列表 2个 何排序 排序 | 更新日期: 2023-09-27 17:50:57
我有一个Step
类和AutoStep
类
class Step {
int StepNumber;
}
class AutoStep {
int StepNumber;
}
NOT继承自任何类,CANNOT继承自任何类。
我必须按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
。
由于不能修改这两个类中的任何一个,因此需要使用Adapter模式为这些类型创建这些接口的实现:
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();
}
您可以使用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);