声明已实现的接口或 class 的 IEnumerable 已过时
Declare implemented IEnumerable of an interface or of a class as obsolete
是否可以将接口或 class 的派生或实现的 IEnumerable 部分声明为已过时,而 class 或接口的其余部分仍然是最新的?我该如何申报?
interface Foo : IEnumerable<Bar>{
int SomethingNonObsolete{
get;
}
}
在上面的示例中,我希望使用已实现的 IEnumerable 的迭代器会导致编译器过时警告,而使用接口本身或使用 SomethingNonObsolete
-属性 不会导致这样的警告。
以下代码应该导致编译器过时警告
foreach(var bar in myFooImplementingInstance){
以下代码不应导致编译器过时警告
myFooImplementingInstance.SomethingNonObsolete.ToString()
更新
因为有很多答案,但每个答案都只关注问题的一部分,这里做一个总结和最后的声明:
最后,由于 LINQ,技术上是不可能的。
如果无论如何都要使用它,正如 Panda 在他的回答中所展示的那样,classes 很容易做到。声明枚举器已过时,您可以罚款。
[Obsolete]
IEnumerator<Bar> GetEnumerator()
[Obsolete]
IEnumerator IEnumerable.GetEnumerator()
对于接口,可以用类似的方式完成,正如 Bozhidar 在评论中所说的那样。使用新关键字声明枚举器并将其标记为过时。
[Obsolete]
new IEnumerator<ITabularDataRow> GetEnumerator();
然而,虽然这两个版本通常都在做它们应该做的事情,但在使用 LINQ 时它们都会出错。
因此,答案似乎是不可能以全面的方式进行,而且在大多数情况下这是好的(参见 MDeSchaepmeester 的回答和评论)。
您可以使用 ObsoleteAttribute
将成员标记为过时。将它添加到每个过时的方法中,您将收到警告(或错误,具体取决于参数)。但是,这意味着您需要指定所有成员 - 除了实现 Foo
的实例外,这在您的情况下是不可能的。您唯一的其他选择是将整个界面标记为过时,并将其替换为 Foo2
- 事实上,无论如何这可能是解决此问题的最佳方法。
另外请注意,这只会处理直接调用。编译器无法知道 ((IEnumerable<Bar>)yourFooInstance).GetEnumerator()
应该过时。
在实现接口时,在 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;
这是一个有趣的情况,但是您要做的是对您的 API 进行相当重大的更改。
Obsolete
主要用于您可以 提供替代方案 的情况,例如通过 XML 文档(例如,如果您将 SomethingNotObsolete
标记为 Obsolete
并说 use SomethingNew instead
.
您要对 API 进行的更改将需要您的消费者进行代码重组,而不是简单地替换方法调用。因此,您应该为(理想情况下)您的 API 的主要版本保留它,并为您的消费者记录迁移路径。
我用一句话说的是 Obsolete
在您的情况下在语义上不正确。
您可以创建一个新界面。现在,在您的新界面中,您不会继承 IEnumerable
并创建原始界面 Obsolete
。现在,无论谁使用 foreach(Foo f in myFooImplementingInstance)
,都会收到您的过时消息。理想情况下,您还应该添加一个提示,提示应该改用新接口。基本思想是您的界面只有一个目的。改变它的继承链或类似的东西将以一种高度不可预测的方式破解目的。因此,您应该创建一个提供新要求的新界面。
不过,我同意@MDeSchaepmeester,这是一个重大的重组,应该有详细的记录。这样做将大量重构消费者代码,因此应谨慎计划和实施。
是否可以将接口或 class 的派生或实现的 IEnumerable 部分声明为已过时,而 class 或接口的其余部分仍然是最新的?我该如何申报?
interface Foo : IEnumerable<Bar>{
int SomethingNonObsolete{
get;
}
}
在上面的示例中,我希望使用已实现的 IEnumerable 的迭代器会导致编译器过时警告,而使用接口本身或使用 SomethingNonObsolete
-属性 不会导致这样的警告。
以下代码应该导致编译器过时警告
foreach(var bar in myFooImplementingInstance){
以下代码不应导致编译器过时警告
myFooImplementingInstance.SomethingNonObsolete.ToString()
更新
因为有很多答案,但每个答案都只关注问题的一部分,这里做一个总结和最后的声明:
最后,由于 LINQ,技术上是不可能的。
如果无论如何都要使用它,正如 Panda 在他的回答中所展示的那样,classes 很容易做到。声明枚举器已过时,您可以罚款。
[Obsolete]
IEnumerator<Bar> GetEnumerator()
[Obsolete]
IEnumerator IEnumerable.GetEnumerator()
对于接口,可以用类似的方式完成,正如 Bozhidar 在评论中所说的那样。使用新关键字声明枚举器并将其标记为过时。
[Obsolete]
new IEnumerator<ITabularDataRow> GetEnumerator();
然而,虽然这两个版本通常都在做它们应该做的事情,但在使用 LINQ 时它们都会出错。 因此,答案似乎是不可能以全面的方式进行,而且在大多数情况下这是好的(参见 MDeSchaepmeester 的回答和评论)。
您可以使用 ObsoleteAttribute
将成员标记为过时。将它添加到每个过时的方法中,您将收到警告(或错误,具体取决于参数)。但是,这意味着您需要指定所有成员 - 除了实现 Foo
的实例外,这在您的情况下是不可能的。您唯一的其他选择是将整个界面标记为过时,并将其替换为 Foo2
- 事实上,无论如何这可能是解决此问题的最佳方法。
另外请注意,这只会处理直接调用。编译器无法知道 ((IEnumerable<Bar>)yourFooInstance).GetEnumerator()
应该过时。
在实现接口时,在 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;
这是一个有趣的情况,但是您要做的是对您的 API 进行相当重大的更改。
Obsolete
主要用于您可以 提供替代方案 的情况,例如通过 XML 文档(例如,如果您将 SomethingNotObsolete
标记为 Obsolete
并说 use SomethingNew instead
.
您要对 API 进行的更改将需要您的消费者进行代码重组,而不是简单地替换方法调用。因此,您应该为(理想情况下)您的 API 的主要版本保留它,并为您的消费者记录迁移路径。
我用一句话说的是 Obsolete
在您的情况下在语义上不正确。
您可以创建一个新界面。现在,在您的新界面中,您不会继承 IEnumerable
并创建原始界面 Obsolete
。现在,无论谁使用 foreach(Foo f in myFooImplementingInstance)
,都会收到您的过时消息。理想情况下,您还应该添加一个提示,提示应该改用新接口。基本思想是您的界面只有一个目的。改变它的继承链或类似的东西将以一种高度不可预测的方式破解目的。因此,您应该创建一个提供新要求的新界面。
不过,我同意@MDeSchaepmeester,这是一个重大的重组,应该有详细的记录。这样做将大量重构消费者代码,因此应谨慎计划和实施。