2017-01-20 4 views
2

У меня есть класс (Foo), которая требуется для сравнения T объектов типа, однако T не всегда может реализовать IComparable и конструктор должен быть в состоянии использовать с нулевым comparer паров. Для того, чтобы поймать это на создание Foo я попытался следующее:Обеспечения действительный IComparer используется

public sealed class Foo<T> 
{ 

    private readonly IComparer<T> _comparer; 

    public Foo(IComparer<T> comparer) 
    { 
     _comparer = comparer ?? Comparer<T>.Default; 
     if (_comparer == null) 
      throw new NotSupportedException("A comparer was not passed for T and no default was found for T. "); 

    } 
} 

Я предположил (ошибочно), что Comparer<T>.Default будет нулевым, если объект не реализовать IComparable<T>, но вместо этого Default будет возвращать действительный Comparer, который бросает ArgumentsException когда сравнение называется, и я не смог найти решение путем исследования того, как подойти к этой ситуации.

Как подойти к этой ситуации?

EDIT: Для уточнения Этот класс должен иметь возможность сортировать объекты типа T с использованием данного Comparer. Но T может не всегда иметь IComparable, но когда предоставляется Comparer, он должен все же иметь возможность сортировать те ограничения объектов, которые нарушили бы это требование. Однако, если переданное в Comparer значение null, то оно должно попытаться использовать Default. Если объект IComparable, все хорошо, если он не должен бросать NotSupportedException.

+2

Проверить MSDN страницы для Comparer (T) .Default: https://msdn.microsoft.com/en-us/library/azhsac5f(v=vs.110).aspx. В частности, в примечаниях упоминается следующее: «Если тип T не реализует общий интерфейс System.IComparable , это свойство возвращает Comparer , который использует интерфейс System.IComparable." –

+0

Может ли что-то вроде этого помочь в вашем случае: http://stackoverflow.com/a/503359/6741868? Не проверял. –

+0

Я сделал ошибку, не глядя на документацию в первую очередь. :/Я видел этот пост в своих путешествиях, но я не был уверен, что он соответствует тому, что я пытался сделать. Принятый ответ кажется более чистым. – BarelyTilted

ответ

1

Основываясь на вашем обновленном вопросе, плохо дайте новый ответ.

public Foo(IComparer<T> comparer) 
{ 
    _comparer = comparer ?? 
        typeof(IComparable<T>).IsAssignableFrom(typeof(T)) 
        ? Comparer<T>.Default : null; 
    if (_comparer == null) 
     throw new NotSupportedException("A comparer was not passed for T and no default was found for T. "); 

} 

Как никогда я не предпочитаю линейное решение. Следующие выглядит чище IMO

public Foo(IComparer<T> comparer) 
{ 
    if(comparer == null) 
    { 
     if(typeof(IComparable<T>).IsAssignableFrom(typeof(T)) 
     { 
      comparer = Comparer<T>.Default; 
     } 
     else 
      throw new NotSupportedException("A comparer was not passed for T and no default was found for T. "); 
    } 

    _comparer = comparer; 


} 
+0

Это работает как шарм, я использую .NET-Core и, по-видимому, немного более подробный, мне пришлось получить 'TypeInfo' first' (typeof (IComparer ) .GetTypeInfo(). IsAssignableFrom (typeof (T)) 'кроме того. Выполняет его цель отлично! – BarelyTilted

+0

@BarelyTilted Я думаю, что вы ошибаетесь. Вы должны использовать **' IComparable '** не' IComparer ':) –

+0

У меня действительно есть! Я был взволнован, что он работал, и не дважды проверял ха-ха. Хотя мои тесты показывают, что оба способа работают для того, что мне нужно. – BarelyTilted

0

Вы можете также рассмотреть вопрос об изменении кода следующим образом, снова с помощью отражения:

  • Для данной Type T выборки всех Interfaces реализованы, и проверьте, есть IComparer<T> и, соответственно, изменить код

    public sealed class Foo<T> 
    { 
        private readonly IComparer<T> _comparer; 
    
        public Foo(IComparer<T> comparer) 
        { 
    
        _comparer = comparer ?? (typeof(T).GetInterfaces().Any(val => val == typeof(IComparer<T>)) 
           ? Comparer<T>.Default : null); 
        if (_comparer == null) 
         throw new NotSupportedException("A comparer was not passed for T and no default was found for T. ");  
        } 
    } 
    
Смежные вопросы