这真的非常让我感到不安,所以我希望有人能给我一个合理的理由来解释为什么事情是这样的。

NotImplementedException。 你在拉我的腿,对吗?

不,我不会说:“坚持使用该方法 - 它引发了notimplemplededexception。”是的,是的,您必须实现抛出NotimplempledException的方法(与C ++中的纯虚拟函数调用不同 - 现在这是有道理的!)。虽然这非常有趣,但我脑子里有一个更严重的问题。

我只是想知道,在存在 NotImplementedException 的情况下,任何人都可以使用 .Net 做任何事情吗?您是否希望用 try catch 块包装每个抽象方法调用以防止可能未实现的方法?如果你捕获到这样的异常,你到底应该怎么处理它?

我认为没有办法在不调用方法的情况下测试它是否实际实现。由于调用它可能会产生副作用,因此我无法预先完成所有检查,然后运行我的算法。我必须运行我的算法,捕获 NotImplementedExceptions 以及如何将我的应用程序回滚到某个正常状态。

这很疯狂。疯狂的。疯狂的。所以问题是: 为什么会出现NotImplementedException?

作为先发制人的罢工,我不希望任何人回应:“因为设计师需要将其放入自动生成的代码中。”这太可怕了。我宁愿在您提供实现之前不编译自动生成的代码。例如,自动生成的实现可以“抛出NotimplempledException”; notimplemplededException未定义的地方!

有人曾经捕获并处理过 NotImplementedException 吗?您是否曾经在代码中留下过 NotImplementedException?如果是这样,这是否代表了一个定时炸弹(即,您不小心将其留在那里),或者是一个设计缺陷(该方法不应该被实现并且永远不会被调用)?

我也非常怀疑 NotSupportedException...不支持?什么?如果不支持,为什么它是您界面的一部分?Microsoft 的任何人都可以拼写不正确的继承吗?但如果我没有因为这个问题而受到太多虐待的话,我可能会为此提出另一个问题。

附加信息:

是关于这个主题的有趣读物。

似乎有很强的共识 布拉德·艾布拉姆斯 “NotImplementedException 是针对尚未实现但确实应该(并且将会)实现的功能。就像你可能会做的那样 开始 当你构建一个类时,获取所有抛出 NotImplementedException 的方法,然后用真实的代码将它们清除......”

评论来自 贾里德·帕森斯 非常弱,应该被忽略:未实现异常:当类型由于任何其他原因未实现方法时抛出此异常。

微软软件定义网络 在这个主题上甚至更弱,仅仅指出“当请求的方法或操作未实现时抛出的异常”。

有帮助吗?

解决方案

有一种情况我觉得很有用:时分驱动。

我编写测试,然后创建存根以便编译测试。这些存根除了 throw new NotImplementedException();. 。这样,无论如何,测试都会默认失败。如果我使用一些虚拟返回值,它可能会产生误报。现在所有测试都会编译并由于没有实现而失败,我将处理这些存根。

因为我从来没有使用过 NotImplementedException 在任何其他情况下,不 NotImplementedException 将永远传递到发布代码,因为它总是会导致某些测试失败。

你不需要到处抓它。好的 API 会记录抛出的异常。这些是您应该寻找的。

编辑:我编写了 FxCop 规则来查找它们。

这是代码:

using System;
using Microsoft.FxCop.Sdk;

/// <summary>
/// An FxCop rule to ensure no <see cref="NotImplementedException"/> is
/// left behind on production code.
/// </summary>
internal class DoNotRaiseNotImplementedException : BaseIntrospectionRule
{
    private TypeNode _notImplementedException;
    private Member _currentMember;

    public DoNotRaiseNotImplementedException()
        : base("DoNotRaiseNotImplementedException",
               // The following string must be the assembly name (here
               // Bevonn.CodeAnalysis) followed by a dot and then the
               // metadata file name without the xml extension (here
               // DesignRules). See the note at the end for more details.
               "Bevonn.CodeAnalysis.DesignRules",
               typeof (DoNotRaiseNotImplementedException).Assembly) { }

    public override void BeforeAnalysis()
    {
        base.BeforeAnalysis();
        _notImplementedException = FrameworkAssemblies.Mscorlib.GetType(
            Identifier.For("System"),
            Identifier.For("NotImplementedException"));
    }

    public override ProblemCollection Check(Member member)
    {
        var method = member as Method;
        if (method != null)
        {
            _currentMember = member;
            VisitStatements(method.Body.Statements);
        }
        return Problems;
    }

    public override void VisitThrow(ThrowNode throwInstruction)
    {
        if (throwInstruction.Expression != null &&
            throwInstruction.Expression.Type.IsAssignableTo(_notImplementedException))
        {
            var problem = new Problem(
                GetResolution(),
                throwInstruction.SourceContext,
                _currentMember.Name.Name);
            Problems.Add(problem);
        }
    }
}

这是规则元数据:

<?xml version="1.0" encoding="utf-8" ?>
<Rules FriendlyName="Bevonn Design Rules">
  <Rule TypeName="DoNotRaiseNotImplementedException" Category="Bevonn.Design" CheckId="BCA0001">
    <Name>Do not raise NotImplementedException</Name>
    <Description>NotImplementedException should not be used in production code.</Description>
    <Url>http://stackoverflow.com/questions/410719/notimplementedexception-are-they-kidding-me</Url>
    <Resolution>Implement the method or property accessor.</Resolution>
    <MessageLevel Certainty="100">CriticalError</MessageLevel>
    <Email></Email>
    <FixCategories>NonBreaking</FixCategories>
    <Owner></Owner>
  </Rule>
</Rules>

要构建它,您需要:

  • 参考 Microsoft.FxCop.Sdk.dllMicrosoft.Cci.dll

  • 将元数据放入名为的文件中 DesignRules.xml 并将其作为嵌入资源添加到程序集中

  • 为您的程序集命名 Bevonn.CodeAnalysis. 。如果要对元数据或程序集文件使用不同的名称,请确保相应地将第二个参数更改为基本构造函数。

然后只需将生成的程序集添加到您的 FxCop 规则中,并从您宝贵的代码中删除那些该死的异常。在某些极端情况下,当抛出异常时,它不会报告 NotImplementedException,但我真的认为,如果您实际上正在编写这样的 cthulhian 代码,那么您是没有希望的。对于正常用途,即 throw new NotImplementedException();, ,它有效,这才是最重要的。

其他提示

它支持一个相当常见的用例,一个有效但只能部分完成的API。说我希望开发人员测试和评估我的API - WashDishes(),至少在我的机器上工作,但我还没有编写代码 DryDishes(),更不用说 PutAwayDishes()了。我可以非常清楚为什么 DryDishes()不起作用而不是默默地失败,或者给出一些神秘的错误信息 - 我还没有实现它。

它的姐妹异常 NotSupportedException 主要用于提供者模型。许多洗碗机具有烘干功能,因此属于界面,但我的折扣洗碗机不支持它。我可以通过 NotSupportedException

告知它

我会在一个地方总结我对此的看法,因为它们分散在几条评论中:

  1. 使用 NotImplementedException 来指示接口成员尚未实现,但将是。您可以将其与自动化单元测试或QA测试结合起来,以确定仍需要实施的功能。

  2. 实现该功能后,您将删除 NotImplementedException 。为该功能编写了新的单元测试,以确保其正常工作。

  3. NotSupportedException 通常用于不支持对特定类型没有意义的功能的提供程序。在这些情况下,特定类型抛出异常,客户端捕获它们并在适当时处理它们。

  4. 框架中存在 NotImplementedException NotSupportedException 的原因很简单:导致它们的情况很常见,因此定义它们是有意义的在框架中,开发人员不必继续重新定义它们。此外,它使客户端更容易知道要捕获的异常(特别是在单元测试的上下文中)。如果你必须定义自己的异常,他们必须找出要捕获的异常,这至少是一个适得其反的时间接收器,并且经常是错误的。

  

为什么NotImplementedException   存在?

NotImplementedException是一个很好的方式来表示尚未准备好的东西。为什么它没有准备好是方法作者的一个单独的问题。在生产代码中你不太可能捕获这个异常,但如果你这样做,你可以立即看到发生了什么,并且比试图弄清楚为什么方法被调用但没有发生甚至更糟 - 接收一些“临时”的情况要好得多。结果并得到“有趣”的副作用。

  

NotImplementedException是C#   相当于Java   UnsupportedOperationException异常?

不,.NET有NotSupportedException

  

我必须运行我的算法,赶上   NotImplementedExceptions和一些   如何将我的应用程序回滚给某些人   理智的状态

Good API具有描述可能异常的XML方法文档。

  

我非常怀疑   NotSupportedException也...不是   支持的?什么?如果不是   支持,为什么它是你的一部分   接口

可能有数百万个原因。例如,您可以引入新版本的API,并且不希望/不能支持旧方法。再次,看到描述性异常而不是深入研究文档或调试第三方代码要好得多。

NotImplementedException异常的主要用途是生成的存根代码:这样你就不会忘记实现它!例如,Visual Studio将显式实现接口的方法/属性,并且主体抛出NotImplementedException。

重新 NotImplementedException - 这有一些用途;它提供了一个例外(例如)您的单元测试可以锁定不完整的工作。但是,它确实做了所说的:这根本不存在(还)。例如,“单声道”对于存在于MS库中的方法,这种方法都会抛出,但尚未编写。

重新 NotSupportedException - 并非所有内容都可用。例如,许多接口支持一对“你可以这样做吗?” /“做这个”。如果“你能这样做吗?”返回false,“do this”是完全合理的。抛出 NotSupportedException 。示例可能是 IBindingList.SupportsSearching / IBindingList.Find()等。

Microsoft的大多数开发人员都熟悉NotImplementedException适合的设计模式。这实际上相当普遍。

一个很好的例子是复合模式,其中许多对象可以被视为单个对象的实例。组件用作(正确)继承的叶类的基本抽象类。例如,File和Directory类可以从相同的抽象基类继承,因为它们是非常相似的类型。这样,它们可以被视为一个单独的对象(当你考虑什么文件和目录时这是有意义的 - 例如在Unix中,一切都是文件)。

因此,在此示例中,Directory类将有一个GetFiles()方法,但是,File类不会实现此方法,因为这样做没有意义。相反,您会收到NotImplementedException,因为File没有像Directory那样生成子项。

请注意,这不仅限于.NET - 您会在许多OO语言和平台中遇到这种模式。

为什么你觉得需要抓住每一个可能的例外?你用 catch(NullReferenceException ex)包装每个方法调用吗?

stub code throwing NotImplementedException 是一个占位符,如果它要发布它应该是bug,就像 NullReferenceException 一样。

我认为MS在框架中添加NotImplementedException的原因有很多:

  • 作为一种方便;既然许多开发人员在开发过程中都需要它,为什么每个人都必须自己推出呢?
  • 这样工具就可以依赖它的存在;例如,Visual Studio 的“实现接口”命令生成抛出 NotImplementedException 的方法存根。如果它不在框架中,则这是不可能的,或者至少相当尴尬(例如,它可能生成在您添加自己的 NotImplementedException 之前无法编译的代码)
  • 鼓励一致的“标准实践”

Frankodwyer 认为 NotImplementedException 是一个潜在的定时炸弹。我想说,任何未完成的代码都是定时炸弹,但 NotImplementedException 比其他替代方案更容易解除。例如,您可以让构建服务器扫描源代码以查找此类的所有使用,并将它们报告为警告。如果您想真正禁止它,您甚至可以在源代码控制系统中添加一个预提交挂钩,以防止签入此类代码。

当然,如果您推出自己的 NotImplementedException,则可以将其从最终构建中删除,以确保不留下定时炸弹。但这只有在整个团队中一致使用自己的实现时才有效,并且必须确保在发布之前不要忘记将其删除。此外,您可能会发现无法删除它;也许有一些可接受的用途,例如测试未交付给客户的代码。

实际上没有理由捕获 NotImplementedException。当被击中时,它应该杀死你的应用程序,并且这样做非常痛苦。修复它的唯一方法不是捕获它,而是更改源代码(实现被调用的方法或更改调用代码)。

有两个原因:

  1. 在开发过程中删除了方法,并抛出异常以提醒开发人员他们的代码编写没有完成。

  2. 实现子类接口,该接口在设计上不实现继承的基类或接口的一个或多个方法。 (有些界面太笼统了。)

这对我来说听起来像是一个潜在的雷区。在遥远的过去,我曾经在一个多年来一直运行的遗留网络系统上工作过一天。当我们跟踪问题时,我们发现一些代码显然没有完成,哪些代码无法工作 - 字面意思是,程序员在编码过程中被打断了。很明显,这个特定的代码路径从未被采用过。

墨菲定律说,类似的东西只是在NotImplementedException的情况下发生。在TDD等的这些日子里,它应该在发布之前被选中,并且至少你可以在发布之前为该异常编写grep代码,但仍然如此。

在测试时很难保证每个案例的覆盖率,这听起来像是通过编写可能是编译时问题的运行时问题而使您的工作更难。 (我认为类似的“技术债务”伴随着严重依赖'鸭子打字'的系统,而我承认它们非常有用。)

COM interop需要此例外。 它是E_NOTIMPL 。链接的博客还显示了其他原因

抛出 NotImplementedException 是IDE生成编译存根代码的最合理方式。就像扩展界面并让Visual Studio为你存根一样。

如果你做了一些C ++ / COM,那里也存在,除了它被称为 E_NOTIMPL

有一个有效的用例。如果您正在处理接口的特定方法,则需要编译代码以便进行调试和测试。根据您的逻辑,您需要从接口中删除该方法并注释掉非编译存根代码。这是一种非常原教旨主义的方法,虽然它具有优点,但不是每个人都会或应该坚持这一点。此外,大多数时候您希望界面完整。

有一个NotImplementedException可以很好地识别哪些方法还没有准备好,在一天结束时就像按 Ctrl + Shift + F 一样轻松找到它们,我也确定静态代码分析工具也会把它拿起来。

您不打算发布具有 NotImplementedException 异常的代码。如果您认为不使用它可以让您的代码变得更好,那么您可以采取更有成效的措施来提高源代码质量。

<强> NotImplementedException

未实现请求的方法或操作时抛出异常。

使这个在.NET核心中定义的单个异常使得查找和根除它们变得更容易。如果每个开发人员都应该创建自己的 ACME.EmaNymton.NotImplementedException ,那么很难找到所有这些。

<强> NotSupportedException异常

当不支持调用的方法时抛出异常。

例如,当尝试读取,搜索或写入不支持调用功能的流时。

例如,生成的迭代器(使用 yield 关键字)是-a IEnumerator ,但 IEnumerator.Reset 方法抛出 NotSupportedException

来自ECMA-335,CLI规范,特别是CLI库类型,System.NotImplementedException,备注部分:

“本标准中其他地方指定的许多类型和构造不需要仅符合内核配置文件的CLI实现。例如,浮点功能集由浮点数据类型System.Single和System.Double组成。如果从实现中省略对这些的支持,则任何引用包含浮点数据类型的签名的尝试都会导致System.NotImplementedException类型的异常。“

因此,该异常仅适用于仅实现最小一致性配置文件的实现。所需的最小配置文件是内核配置文件(参见ECMA-335第4版 - 第IV部分,第3节),其中包括BCL,这就是为什么例外包含在“核心API”中,而不是在某些其他位置。

使用异常来表示存根方法,或者对于缺少实现的设计器生成的方法,是误解了异常的意图。

至于为什么MS的MSDN文档中没有包含这些信息,CLI的实现超出了我的范围。

我不能保证NotImplementedException(我主要同意你的观点)但我在工作中使用的核心库中广泛使用了NotSupportedException。例如,DatabaseController允许您创建任何受支持类型的数据库,然后在代码的其余部分使用DatabaseController类,而不必过多关注下面的数据库类型。相当基本的东西吧? NotSupportedException派上用场的地方(如果还没有,我将使用自己的实现)是两个主要的实例:

1)将应用程序迁移到其他数据库 人们经常认为这很少,如果有的话,发生或需要。瞎扯淡。了解更多。

2)相同的数据库,不同的驱动程序 最近的一个例子是使用Access支持的应用程序从WinXP升级到Win7 x64的客户端。由于没有64位JET驱动程序,他们的IT人员安装了AccessDatabaseEngine。当我们的应用程序崩溃时,我们可以很容易地从日志中看到DB.Connect与NotSupportedException崩溃 - 我们很快就能解决这个问题。最近的另一个例子是我们的程序员之一试图在Access数据库上使用事务。即使Access支持事务,我们的库也不支持Access事务(出于本文范围之外的原因)。 NotSupportedException,是你发光的时候了!

3)通用功能 我无法想到一个简洁的“来自经验”这里有一个例子,但是如果你想到一个类似于添加电子邮件附件的功能的东西,你希望它能够获取一些常见的文件,如JPEG,从各种流类派生的任何东西,以及几乎任何有“。”的东西。的ToString&QUOT;方法。对于后一部分,您当然无法考虑所有可能的类型,因此您将其设为通用。当用户传递OurCrazyDataTypeForContainingProprietarySpreadsheetData时,使用反射来测试是否存在ToString方法并返回NotSupportedException以指示缺少对不支持ToString的所述数据类型的支持。

NotSupportedException绝不是一个至关重要的功能,但是当我在大型项目上工作时,我发现自己使用了更多东西。

假设您在生产代码中使用此方法

public void DoSomething()

如果你想稍后离开它,你会选择哪一个?

public void DoSomething()
{
}

public void DoSomething()
{
    throw new NotImplementedException();
}

我肯定会选择第二个。与Elmah或您拥有的任何错误记录机制相结合(作为整个应用程序的一个方面实现)。与日志/异常过滤一起触发一个被捕获时的重大错误电子邮件通知。

NotImplementedException ==未完成的参数也不正确。 (1)未实现方法的捕获应留给单元测试/集成测试。如果你有100%的覆盖率(你现在应该这么做,有这么多的模拟/存根/代码生成工具)没有NotImplementedException,你有什么担忧? (2)代码生成。简单明了。同样,如果我生成代码,并且只使用生成的代码的一半,为什么我不会在生成的存根的其余部分中使用NotImplementedException?

这就像说代码不应该编译,除非每个可以为空的输入都应该被检查/处理为null。 (AKA万亿美元的错误,如果不是更多)。语言应该是灵活的,而测试/合同应该是可靠的。

我很少使用它进行界面修复。假设你有一个你需要遵守的界面,但任何人都不会调用某个方法,所以只要坚持一个NotImplementedException,如果有人调用它,他们就会知道他们做错了。

针对.NET的某些方法抛出NotImplementedException(请参阅Code DOM中的解析器C#,该解析器未实现,但该方法存在!) 您可以使用此方法验证Microsoft.CSharp.CSharpCodeProvider.Parse

它们都是针对两个常见问题的黑客。

NotImplementedException是针对架构宇航员的开发人员的解决方法,他们喜欢先写下API,然后再编写代码。显然,由于这不是一个增量过程,你不能一次实现所有,因此你想通过抛出NotImplementedException假装你已经完成了。

NotSupportedException是对C#和Java中类型系统限制的破解。在这些类型的系统中,你说Rectangle'是'Shape iff Rectangle继承了Shapes的所有特性(包括成员函数+变量)。但是,在实践中,情况并非如此。例如,Square是一个Rectangle,但Square是Rectangle的限制,而不是泛化。

因此,当您想要继承和限制父类的行为时,您会在对限制没有意义的方法上抛出NotSupported。

原型或未完成的项目怎么样?

我认为使用异常并不是一个坏主意(尽管我在这种情况下使用了消息框)。

嗯,我有点同意。如果一个接口的制作方式不是所有的类都可以实现它的所有部分,那么它应该在我看来已经被分解了。

如果IList可以修改或不能修改,它应该被分解为两个,一个用于不可修改的部分(getter,lookup等),另一个用于可修改的部分(setter,add,remove等)。 )。

我的代码中有一些NotImplementedExceptions。通常它来自接口或抽象类的一部分。我认为将来可能需要的一些方法,它们作为课程的一部分是有意义的,但我只是不想花时间添加,除非我真的需要它。例如,我的游戏中有各种各样的统计数据的界面。其中一种是ModStat,它是基本属性加上所有修饰符(即武器,护甲,法术)的总和。我的stat接口有一个OnChanged事件,但是我的ModStat通过计算每次调用它引用的所有统计数据的总和来工作。因此,每次stat更改时都不会产生大量ModStat.OnChange事件的开销,如果有人试图向OnChange添加/删除监听器,我只会抛出NotImplementedException。

.NET语言都与生产力有关,那么为什么要花时间编写一些你甚至不会使用的东西呢?

这是一个例子:在Java中,无论何时实现接口 Iterator ,都必须覆盖显而易见的方法 hasNext() next(),但也有 delete()。在99%的用例中,我不需要这个,所以我只抛出 NotImplementedException 。这比默默地无所事事要好得多。

NotImplementedException仅用于促进开发。想象一下,你开始实现一个接口。在移动到下一个方法之前,您希望能够在完成实现一个方法时至少构建。 使用NotImplementedExceptions对NotImplemented方法进行存储是一种很好的生存未完成代码的方法,以后很容易发现。否则,您将面临快速实施您可能忘记解决的问题的风险。

如果您不想使用它,请忽略它。如果你有一块代码块,它的成功取决于它的每一块成功,但它可能会失败,那么你唯一的选择是捕获基本的 Exception 并回滚需要回滚的内容。忘记 NotImplementedException 。可能会抛出大量异常,例如 MyRandomException GtfoException OmgLolException 。在您最初编写代码之后,我可以从您调用的API中抛出另一个异常类型。编写代码时不存在的一个。处理你知道如何处理和回滚其他任何人,即 catch(Exception)。这很简单,我想......我发现它也派上用场了。特别是当你用语言/框架尝试花哨的东西时偶尔会强迫你。

我的一个例子是序列化。我在我的.NET库中添加了数据库中不存在的属性(例如,对现有的“哑”属性的方便包装,例如组合 FirstName的 FullName 属性 MiddleName LastName )。然后我想将这些数据类型序列化为XML以通过线路发送它们(例如,从ASP.NET应用程序发送到JavaScript),但是序列化框架仅使用 get 和<来序列化公共属性。 code> set 访问器。我不希望你能够设置 FullName 因为那时我必须解析它,并且可能有一些无法预料的格式我错误地解析并且数据完整性消失了。为此只使用底层属性更容易,但由于语言和API要求我拥有 set 访问器,我将抛出 NotImplementedException (我不是知道 NotSupportedException ,直到我读到这个线程,但任何一个工作),以便如果一些程序员尝试设置 FullName ,他将在测试期间遇到异常意识到自己的错误。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top