排序项目列表的通用方法

时间:2019-03-21 13:55:26

标签: c# generics

我有两个具有两个公共属性IdSortNumber的类。我想有一个通用的方法来对所述类列表中的项目进行排序。

是否可以实现类IOrderitemFoo的接口Bar,但仍然可以使用方法MoveUp

还是reflection是唯一的选择?过去几年来一直在编写TypeScript代码,因此对C#有点生锈。

public class Foo
{
   public int Id {get;set;}
   public int SortNumber {get;set;}
   // etc
} 

public class Bar
{
   public int Id {get;set;}
   public int SortNumber {get;set;}
   // etc
}

public interface IOrderitem
{
   int Id {get;set;}
   int SortNumber {get;set;}    
}

public static void MoveUp<T>(List<T> itemList, int id)
{
    for (int i = 0; i < itemList.Count; i++)
    {
        // reindex items
        var item = itemList[i] as IOrderItem;

        bool isItem = item.Id == id;

        if (isItem && i > 0)
        {
            // set item above eventinfo item to one position lower (0 = top rest lower)
            (itemList[i - 1] as IOrderItem).SortNumber = i;

            // set the item to move up one position higher (0 = top rest lower)
            item.SortNumber = i - 1;
            i++;
        }
        else
        {
            item.SortNumber = i;
        }
    }
}

2 个答案:

答案 0 :(得分:0)

您可以为Foo和Bar实现一个基类,并从其继承。

public class BaseClass
{
    public int Id { get; set; }
    public int SortNumber { get; set; }
    // etc
}
class Foo : BaseClass    {    }
class Bar : BaseClass    {    }

您可以使用动态方法来代替创建具有已定义类型的T列表。但是我不建议这样做。不推荐。请参阅链接Is the use of dynamic considered a bad practice?

 public static void MoveUp(List<dynamic> itemList, int id)
    {
       // ....
    }

然后您可以照常使用“属性”,但是以后重命名都可能导致崩溃。

实际上,所有取决于您的目的是不使用接口,这对我来说并不明确。

答案 1 :(得分:0)

您在评论中写道:

  

我想知道是否可以在没有接口-或-基类-或-抽象类的情况下完成。我正在使用不希望更改的通用项目中存在的EF类。

因此,您需要使用鸭子打字功能。

C#是一种强类型语言。鸭子打字是一种动态语言功能。尽管有duck typing in the C# compiler itself的一些示例(例如,参见foreachawait),但是鸭子类型的广泛使用打破了强类型语言的目的:编译时类型安全。

有两种方法可以在C#中实现它:使用Reflection或dynamic。两者都很慢。

我可以向您展示dynamic的方法。

在您的MoveUp<T>方法中,使用

var item = itemList[i] as dynamic;

代替

var item = itemList[i] as IOrderItem;

所以现在T甚至可以是typeof(object)。您可以访问IdSortNumber属性-它们仅需要存在于该对象上。 但是:这有点放弃了使用泛型获得的所有好处。

缺点:

  • sloooow
  • 没有编译时类型的安全性
  • 没有自动重构和其他有趣的IDE
  • 如果没有此类属性,类型错误或只读等,则需要处理异常

我为您创建了一个简单的基准。我有一个List<Item>,带有10.000个对象。我这样做:

for (int i = 0; i < 10_000; i++)
{
    sum += objects[i].Value;
}

for (int i = 0; i < 10_000; i++)
{
    dynamic o = objects[i] as dynamic;
    sum += o.Value;
}

结果是:

|     Method |      Mean |     Error |    StdDev |
|----------- |----------:|----------:|----------:|
| Direct     |  11.22 us | 0.0268 us | 0.0251 us |
| Dynamic    | 256.15 us | 0.9606 us | 0.8986 us |

因此dynamic方法的速度要慢23倍(在我的机器上,使用.NET Framework 4.7.2(CLR 4.0.30319.42000),64位RyuJIT-v4.7.3324.0)。