Общая проблема с реализацией IComparable в Mono

#c# #mono #unity3d #compareto #icomparable

#c# #mono #unity-игровой движок #сравнение #icomparable

Вопрос:

Этот код успешно выполняется в .NET 4.0

     public void CompareTest()
    {
        var m1 = new Foo { Order = 1 };
        var m2 = new Foo { Order = 2 };
        var c1 = new Bar { Order = -1 };
        var c2 = new Bar { Order = 3 };
        var list1 = new List<IOrderable> { m1, m2, c1, c2 };
        var list2 = new List<Bar> { c1, c2 };
        list1.Sort();
        list2.Sort();
    }

    public interface IOrderable : IComparable<IOrderable>
    {
        int Order { get; set; }
    }

    public class Foo : IOrderable
    {
        public int Order { get; set; }

        public int CompareTo(IOrderable other)
        {
            return Order.CompareTo(other.Order);
        }
    }

    public class Bar : IOrderable
    {
        public int Order { get; set; }

        public int CompareTo(IOrderable other)
        {
            return Order.CompareTo(other.Order);
        }
    }
  

Однако в Mono 2.6 (в Unity3D) она выдает исключение:

 ArgumentException: does not implement right interface
  

Это приводит ко второму виду ( list2.Sort() ), но не к первому

Я вроде как новичок во всех этих сравнениях, поэтому извините, если я упускаю здесь что-то очевидное.

Почему он жалуется на то, что не реализует правильный интерфейс? Она реализована. Есть идеи, что здесь происходит? почему это работает в .NET, но не в Mono?

Спасибо.

РЕДАКТИРОВАТЬ: полный стек

 ArgumentException: does not implement right interface
System.Collections.Generic.Comparer`1 DefaultComparer[ShowEmAll.BetterBehaviourEditor Bar].Compare (ShowEmAll.Bar x, ShowEmAll.Bar y) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Collections.Generic/Comparer.cs:86)
System.Array.compare[Bar] (ShowEmAll.Bar value1, ShowEmAll.Bar value2, IComparer`1 comparer) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System/Array.cs:1744)
System.Array.qsort[Bar,Bar] (.Bar[] keys, .Bar[] items, Int32 low0, Int32 high0, IComparer`1 comparer) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System/Array.cs:1721)
System.Array.Sort[Bar,Bar] (.Bar[] keys, .Bar[] items, Int32 index, Int32 length, IComparer`1 comparer) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System/Array.cs:1674)
Rethrow as InvalidOperationException: The comparer threw an exception.
System.Array.Sort[Bar,Bar] (.Bar[] keys, .Bar[] items, Int32 index, Int32 length, IComparer`1 comparer) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System/Array.cs:1677)
System.Array.Sort[Bar] (.Bar[] array, Int32 index, Int32 length, IComparer`1 comparer) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System/Array.cs:1623)
System.Collections.Generic.List`1[ShowEmAll.BetterBehaviourEditor Bar].Sort () (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Collections.Generic/List.cs:568)
ShowEmAll.BetterBehaviourEditor.CompareTest () (at Assets/Vexe/ShowEmAll/Core/Editor/CustomEditors/BetterBehaviourEditor.cs:81)
ShowEmAll.BetterBehaviourEditor.OnEnable () (at Assets/Vexe/ShowEmAll/Core/Editor/CustomEditors/BetterBehaviourEditor.cs:62)
  

Комментарии:

1. Пожалуйста, покажите полную трассировку стека исключений. Мы понятия не имеем, на что жалуются, когда на данный момент.

2. Итак, какая строка равна 81? list1.Sort() или list2.Sort() ?

3. Я добавил это тоже к своему вопросу, но не к редактированию. Проблема второго рода возникает из-за переполнения стека. list2.Sort()

4. Похоже, что это, вероятно, ошибка Mono, но у меня это работает в Mono 3.3

5. Спасибо Unity за то, что оставили нас с ржавым Mono = (

Ответ №1:

Во-первых, похоже, что это, вероятно, ошибка Mono в Comparer<T>.Default , которую следует заметить, если T реализовать IComparable<Foo> для некоторых Foo , которые являются либо реализациями интерфейса T , либо базовым типом T .

Для обходных путей предлагается четыре варианта:

  • Реализуйте не универсальный IComparable интерфейс в Bar , возможно, просто делегируя реализацию CompareTo(IOrder)
  • Реализуйте IComparable<Bar> в Bar , вероятно, просто делегируя реализацию CompareTo(IOrder)
  • Всегда используйте List<IOrder> , даже если каждый элемент в нем является Bar
  • Укажите Comparer<T> to List<T>.Sort — я подозреваю, что вы можете довольно легко создать свою собственную реализацию с использованием дженериков.

Комментарии:

1. Спасибо! всегда рядом со мной: D