Как указать параметр типа, который НЕ реализует определенный интерфейс? - PullRequest
6 голосов
/ 04 октября 2010

Я разработал несколько методов расширения для объектов, которые я не хочу использовать / показывать в intellisense для объектов, которые реализуют IEnumerable. Концептуально я хочу что-то вроде следующего

public static T SomeMethod<T>(this object value) where T != IEnumerable
        {

        }

Можно ли наложить какие-либо ограничения такого рода в C #?

Редактировать

Извините, я поставил вопрос неправильно. Я знаю допустимые ограничения в C #, я хочу знать, что если есть какой-то другой способ сделать это?

Ответы [ 6 ]

14 голосов
/ 04 октября 2010

Просто чтобы подтвердить комментарий Ойвинда: в C # такого ограничения нет.Единственные типы ограничений:

  • where T : struct (ограничение типа, не допускающего значения NULL)
  • where T : class (ограничение ссылочного типа)
  • where T : SomeClassName(преобразование в конкретное ограничение класса)
  • where T : ISomeInterfaceName (преобразование в определенное ограничение интерфейса)
  • where T : U (преобразование в ограничение другого типа)
  • where T : new() (ограничение конструктора без параметров)

Обратите внимание, что я выделил только определенные ограничения класса и интерфейса, поскольку первое является основным, а второе - вторичным.

1 голос
/ 04 октября 2010

Это не поддерживается.Правовые ограничения перечислены здесь .

0 голосов
/ 04 октября 2010

Вы можете сделать что-то подобное, но только для типов, которыми вы управляете.

Скажем, вы хотите использовать метод, подобный этому:

public static class XmlSerializableExtension {   
  public static string ToXml(this object self) { 
    // ...
  }
}

НоВы не хотите загрязнять каждый объект этим, только подмножество ваших классов.

Вы можете достичь этого следующим образом:

public interface MXmlSerializable { } 
public static class XmlSerializable {   
  public static string ToXml(this MXmlSerializable self) {
    // ...
  }
}

Теперь вы отмечаете те классы, которые хотитеэтот метод для применения с "mixin" интерфейсом:

public class MyClass : MXmlSerializable { 
  // ...
} 

И он будет только в intellisense для этих классов.

0 голосов
/ 04 октября 2010

Вы не можете, и я согласен, что это неприятно, хотя то, что я обнаружил, что мне нужно, это не столько то, что вы ищете, сколько переопределение на основе ограничения (чтобы я мог, например, иметь класс и struct struct того же самого метода или класса, и иметь соответствующую, используемую в зависимости от обстоятельств).

Есть два случая, когда мы можем хорошо жить.

Одна из причин, по которой мы не хотим использовать метод расширения, заключается в том, что он уже предоставлен как метод экземпляра. На самом деле мы получаем это бесплатно; методы экземпляра всегда используются вместо методов расширения (хотя derivedClass.method() не будет использоваться при вызове baseClass.method(), если он существует только в derivedClass).

Другой случай - выбор времени выполнения:

public static T SomeMethod<T>(this object value) where T != IEnumerable
{
  if(typeof(T).GetInterface("IEnumerable") != null)
  {
    //behaviour appropriate for IEnumerable
  }
  else
  {
    //other behaviour.
  }
}

Это не идеально, особенно если единственное «поведение, подходящее для IEnumerable» - это генерировать исключение, но иногда этого может быть достаточно.

0 голосов
/ 04 октября 2010

Как уже упоминалось, то, что вы хотите сделать, не сработает, но вы можете посмотреть, какие типы объектов вы хотите поддерживать, и ограничить их каким-то общим классом / интерфейсом, или вы можете просто необходимо отказаться от общей части и написать несколько методов расширения, чтобы вы могли запретить IEnumerable.

0 голосов
/ 04 октября 2010

Это невозможно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...