2016-06-15 8 views
4

Можно ли объявить производную или реализованную часть IEnumerable интерфейса или класса устаревшим, тогда как остальная часть класса или интерфейса по-прежнему актуальна? Как я объявляю это?Объявить реализованный IEnumerable интерфейса или класса как устаревшего

interface Foo : IEnumerable<Bar>{ 

    int SomethingNonObsolete{ 
     get; 
    } 

} 

В приведенном выше examble, хотелось бы, что использование итераторы реализованного IEnumerable приводит к компилятору устаревших предупреждениям, тогда как использование интерфейса itselfs или использование SomethingNonObsolete -свойства не приводит к такое предупреждение.

Следующий код должен привести к компилятором устаревшие предупреждения

foreach(var bar in myFooImplementingInstance){ 

Следующий код не должно привести к компилятором устаревшие предупреждения

myFooImplementingInstance.SomethingNonObsolete.ToString() 

UPDATE
Потому что есть много ответов, но каждый ответ касается только па rt проблемы, здесь резюме и окончательный отчет:

В конце концов, это технически невозможно из-за LINQ.

Если кто-то будет использовать его в любом случае, как показывает Панда в его ответе, это легко сделать для занятий. Объявите счетчики как устаревшие и ваши штрафы.

[Obsolete] 
IEnumerator<Bar> GetEnumerator() 
[Obsolete] 
IEnumerator IEnumerable.GetEnumerator() 

Для интерфейсов это можно сделать аналогичным образом, как отмечает Божидар в комментарии. Объявите перечислитель новым ключевым словом и отметьте его как устаревший.

[Obsolete] 
new IEnumerator<ITabularDataRow> GetEnumerator(); 

Однако, в то время как обе эти версии делают в общем то, что они должны, они оба разрыва при использовании LINQ. Таким образом, ответ кажется, что это невозможно в комплексном виде и что это в большинстве случаев полезно (см. Ответ и комментарии от MDeSchaepmeester).

+0

Итак, вы в основном хотите удалить интерфейс из своего API? Почему бы не создать новый класс, который не реализует интерфейс? – HimBromBeere

+0

Нет, я хочу удалить IEnumerable из интерфейса, но в настоящее время я не могу этого сделать, потому что многие приложения полагаются на интерфейс. Я хочу запретить разработчикам использовать foreach в IENumerable в новом коде, чтобы в будущем его было легче удалить, и у нас еще нет ссылок. – HCL

+0

Существует способ сделать это с помощью ** точных ** примеров кода в вашем вопросе, но простой перевод в 'IEnumerable' или' IEnumerable 'будет * not * помечен как устаревший и не будет перечислить его. Короче говоря, это не решит все ваши проблемы. –

ответ

4

При реализации своего интерфейса, добавив атрибут на GetEnumerator методы Obsolete, как показано ниже, приводит к вашим ожиданиям:

public class MyClass : Foo 
{ 
    public int SomethingNonObsolete 
    { 
     get 
     { 
      throw new NotImplementedException(); 
     } 
    } 

    [Obsolete] 
    public IEnumerator<Bar> GetEnumerator() 
    { 
     throw new NotImplementedException(); 
    } 

    [Obsolete] 
    IEnumerator IEnumerable.GetEnumerator() 
    { 
     throw new NotImplementedException(); 
    } 
} 

Результат:

var c = new MyClass(); 

// Flagged as obsolete 
foreach (var blah in c) 
{ 

} 

// Not flagged as obsolete 
var s = c.SomethingNonObsolete; 
+2

Стоит отметить, что, хотя это предотвратит успешное выполнение прямого' foreach' без предупреждения, оно ничего не сделает для методов, которые принимают 'IEnumerable' (например, 'c.First())', поэтому значение этого как способа определения того, какие потребители используют реализацию IEnumerable, ограничено. –

+1

Правда, но не пытаясь быть nitpicky, это было не в требованиях :) – Panda

+0

Спасибо, я поддержал, потому что он конструктивен и решает одну часть вопроса. – HCL

2

Вы можете использовать ObsoleteAttribute, чтобы пометить участника как устаревшие. Добавьте его к каждому из ваших устаревших методов, и вы получите свои предупреждения (или ошибки, в зависимости от аргументов). Однако это означает, что вам нужно указать всех членов, что невозможно в вашем случае, кроме случаев, когда выполняется реализация Foo. Единственный другой вариант - пометить весь интерфейс как устаревший и заменить его на Foo2 - на самом деле, это может быть лучший способ обойти это в любом случае.

Также обратите внимание, что это будет касаться только прямых вызовов. Компилятор не знает, что ((IEnumerable<Bar>)yourFooInstance).GetEnumerator() должен быть устаревшим.

+0

Если я правильно понимаю вас, это невозможно на интерфейсе, однако, если я приписываю итераторы конкретного класса, foreach-call будет украшен предупреждением компилятора? – HCL

+0

@HCL Да, потому что 'foreach' читы и вообще не использует интерфейс IEnumerable. С другой стороны, методы LINQ * do * используют 'IEnumerable \' 1', поэтому они вообще не будут видеть ваши устаревшие атрибуты. – Luaan

+1

Совершенно легально * скрыть * GetEnumerator() 'и пометить его атрибутом в определении интерфейса. Используйте ключевое слово 'new' так:' new IEnumerator GetEnumerator(); ' –

0

Это интересная ситуация, но то, что вы это будет довольно значительным изменением для вашего API.

Obsolete используется, в основном, если вы можете использовать вместо альтернативы, т.е. через XML-документ (например, если вы хотите пометить SomethingNotObsolete с Obsolete и сказать use SomethingNew instead.

изменения вы собираетесь внести в свой API потребует реструктуризацию коды ваших потребителей, а не просто заменить вызов метода. Таким образом, вы должны оставляем это для (в идеале) крупный релиз вашего API и документировать путь миграции для ваших потребителей.

То, что я хочу сказать в одном предложении, что Obsolete не семантически правильно в вашей ситуации.

+0

Не уверен, что это правда. Существуют альтернативные способы итерации над баром (над свойствами, возвращающими Ienumerable ). Реализация IEnumerable была дополнительной и только для удобства. Однако он показал, что его присутствие не так приятно. – HCL

+0

Для удобства вы не просто реализуете 'IENumerable' в .NET. Это * стандартный способ общения, что что-то можно повторить. Вы делаете что-то не так, если не можете реализовать его во всем, что должно быть перечислимо. – MarioDS

+0

Спасибо за инструкцию, все еще вопрос возникает. – HCL

0

Вы могли создайте новый интерфейс. Теперь в вашем новом интерфейсе вы не наследуете IEnumerable и iginal интерфейс Obsolete. Теперь whoeever использует foreach(Foo f in myFooImplementingInstance) получает ваше устаревшее сообщение. В идеале вы также добавили намек на то, что вместо этого следует использовать новый интерфейс. Основная идея заключается в том, что ваш интерфейс имеет единственную цель. Изменение его цепочки наследования или аналогичного варианта приведет к значительному непредсказуемости. Поэтому вы должны создать новый интерфейс, который обеспечит новые требования.

Однако я согласен с @MDeSchaepmeester, что это серьезная реструктуризация, которая должна быть хорошо документирована. Это будет иметь массовую реструктуризацию потребительского кода, и поэтому его следует планировать и осуществлять с осторожностью.