【问题标题】:Force input based on interface基于界面的强制输入
【发布时间】:2018-06-20 12:04:10
【问题描述】:

我有一个抽象类,它强制执行一个方法,该方法将接口作为输入,如下所示:

public abstract DocumentWriter
{
    (...)
    protected abstract void FillContent(IDocumentArgs args);
}

创建接口IDocumentArgs 是为了确保参数中包含某些属性,否则这在很大程度上取决于DocumentWriter 的实现。

public interface IDocumentArgs
{
    string Title { get; set; }
    string Subject { get; set; }
    string Author { get; set; }
}

基于这个接口,我做了这个接口的实现,用于DocumentWriter的实现。它看起来像这样:

public class ActualDocumentArgs : IDocumentArgs
{
    // Properties enforced by the interface
    string Title { get; set; }
    string Subject { get; set; }
    string Author { get; set; }

    // Custom properties
    string CustomerName { get; set; }
    DateTime DueDate { get; set; }
    (...)
}

问题是:我想使用ActualDocumentArgs来实现FillContent()(我想这应该是可能的,因为它实现了IDocumentArgs),像这样:

public class ActualDocumentWriter : DocumentWriter
{
    (...)    
    protected override void FillContent(ActualDocumentArgs args)
    {
        // Do stuff
    }
}

但是如果我这样做,我会得到一个编译时错误:

'ActualDocumentWriter.FillContent(ActualDocumentArgs)': 找不到合适的方法来覆盖。

另一方面,我不能使用IDocumentArgs 作为输入,因为那时我将无法访问自定义属性。

如何解决这个问题?让我头疼……

【问题讨论】:

  • 你能DocumentWriter<T> where T : IDocumentArgs 然后protected abstract void FillContent(T args);class ActualDocumentWriter : DocumentWriter<ActualDocumentArgs> 吗?
  • 实现抽象类时不能加强契约。它要求您接受 any IDocumentArgs,而不仅仅是 ActualDocumentArgs。问题是为什么你需要 DocumentWriter 类开始?
  • @DennisKuypers DocumentWriter 包含一些非抽象方法,然后可以由实际实现使用。我不想定义DocumentWriter 的任何实现都应该实现FillContent 方法,该方法接受基于(但不限于)IDocumentsArgs 的输入。这有意义吗?
  • @Noceo 使用抽象类为后代提供实用方法的好选择。在您的情况下,FillDocument 是 protected。那是谁在打电话呢? (也许这不一定是抽象类合同的一部分。如果您将有多种文档信息类型并且您必须找出负责的文档作者是谁,您可以使用stackoverflow.com/questions/50371510/…

标签: c# interface polymorphism abstract-class


【解决方案1】:

您当前的抽象类要求该方法接受任何实现IDocumentArgs 的东西。您可以在传入时检查类型,但编译器本身不会强制执行它。

您可以做的一件事是将抽象类更改为泛型。像这样的:

public abstract class DocumentWriter<T> where T : IDocumentArgs
{
    protected abstract void FillContent(T args);
}

注意类型参数上的where 约束,要求实现类型仅使用IDocumentArgs 的派生类作为类型参数。

然后,当您实现该类时,显式提供类型参数:

public class ActualDocumentWriter : DocumentWriter<ActualDocumentArgs>
{ 
    protected override void FillContent(ActualDocumentArgs args)
    {
        // Do stuff
    }
}

【讨论】:

  • 这似乎有效,但意味着我的接口IDocumentWriter 不再被使用。不过这没什么大不了的,因为它没有什么实际效果。
  • @Noceo:好吧,既然你的原始代码也没有使用IDocumentWriter 接口,我看不出有问题。
【解决方案2】:

您可以使用generic constraint

public abstract DocumentWriter<T>
  where T : IDocumentArgs
{
    (...)
    protected abstract void FillContent(T args);
}

public class ActualDocumentWriter : DocumentWriter<ActualDocumentArgs>
{
    (...)    
    protected override void FillContent(ActualDocumentArgs args)
    {
        // Do stuff
    }
}

【讨论】:

    【解决方案3】:

    我不能使用 IDocumentArgs 作为输入,因为那时我将无法访问自定义属性。

    表示设计错误。 你不应该想要那个。

    你可以绕过它,在 override 方法中你可以对它进行类型转换:

    protected override void FillContent(IDocumentArgs args)
    {
        var actualArgs = args as ActualDocumentArgs ;
        // Do stuff
    }
    

    但这是一个 hack。

    【讨论】:

    • 我们并非总能挑选出理想的设计和界面。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-10
    • 1970-01-01
    • 1970-01-01
    • 2013-02-15
    • 2014-03-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多