【问题标题】:Getting inconsistent accessibility error while trying to have protected constructor in base abstract class with interface injected marked as internal尝试在基抽象类中使用标记为内部的接口注入受保护的构造函数时出现不一致的可访问性错误
【发布时间】:2019-07-15 00:07:12
【问题描述】:

我有 1 个接口 IMetadata,我想限制仅访问当前程序集(类库)而不是外部,因此我将其标记为内部。

现在我想将此接口注入到我的基抽象类中,并在我的基类方法上调用 IMetadata 的方法来执行一些逻辑。例如,基类将从派生类 Type1 接收版本控制,因此我已将基抽象类构造函数标记为受保护,但出现以下错误:

可访问性不一致:参数类型 IMetadata 较少 比 BaseType.BaseType(IMetadata) 更容易访问

但是此元数据将始终从派生类(Type1)接收其具体类型,因此我希望此基类构造函数受保护,并且我希望元数据仅在当前程序集中可用,而不是在它之外。

internal interface IMetadata
{
   string CreateMetadata();
}

internal class Metadata : IMetadata
{
    public Metadata(string location)
    {       
          this.location = location;   
    }
    public string CreateMetadata()
    {
    }
}

public interface IBaseType
{ 
    Void Perform();
} 

public abstract class BaseType : IBaseType
{
   private readonly IMetadata _metadata;
   protected BaseType(IMetadata metadata) //error
   {

   }
}

class Type1 : BaseType
{
    public Type1(IMetadata metadata) : 
    base(metadata)
    {
    }
}

谁能告诉我问题出在哪里以及如何实现这种封装?

【问题讨论】:

  • public 事物不能有不是 public 的依赖项(例如构造函数参数)。 IMetadata 必须是 public。该错误基本上向您解释了这一点。
  • @mjwills 但是问题将是 IMetadata 将在我试图避免的程序集之外被访问。有没有办法实现这两者(防止外部访问 Imetadata 并且还具有受保护的构造函数基础抽象类)?
  • 不,没有。 public / protected 事物不能依赖于 internal 事物。我的意思是,这样做有什么意义?您也可以将其设为internal,因为无论如何它在程序集之外都不会有用。
  • @mjwills 你认为这是造成这个问题的设计缺陷吗?
  • 不,对消费者隐藏实现细节是件好事。

标签: c#


【解决方案1】:

编译器执行这些可访问性检查的原因是试图引导您进入"pit of success"。您已将“事物”标记为(或允许默认)为internal。这意味着它是您的程序集中的一个实现细节。您的装配之外的任何人都不应该知道或关心这个“东西”是什么。它肯定无法“说出它的名字”或创建一个。

然后你写一些publicprotected。这些是其他程序集可见的东西。然后你说“为了使用它,你必须提供一个东西”。你泄露了一个实现细节,这就是编译器阻止你的原因。您需要仔细研究这一点,要么决定它不是纯粹是一个实现细节(因此将其设为public),或者你不应该将它暴露在你的程序集之外。

理想情况下,您将此构造函数标记为 private protected,它具有正确的语义 - 只有 {类继承自此类} 和 {此程序集中的类} 的 intersection 可以调用它。无论如何,只有您程序集的其他成员才能获得所需的实例。

但是,如果您还没有使用 C#7.2,则必须做出选择。我会选择internal。无论如何,它是一个抽象类,即使使用理论上与继承层次无关的构造函数,也没有人可以直接构造它。


这编译得很好并显示了两种方法:

internal interface IMetadata
{
  string CreateMetadata();
}

internal class Metadata : IMetadata
{
  private readonly string location;
  public Metadata(string location)
  {
    this.location = location;
  }
  public string CreateMetadata()
  {
    return string.Empty;
  }
}

public interface IBaseType
{
  void Perform();
}

public abstract class BaseType : IBaseType
{
  private readonly IMetadata _metadata;
  private protected BaseType(IMetadata metadata) //No error
  {

  }

  internal BaseType(IMetadata metadata, int thing) //No error
  {

  }

  public abstract void Perform();
}

class Type1 : BaseType
{
  public Type1(IMetadata metadata) :
  base(metadata)
  {
  }

  public Type1(IMetadata metadata, int thing) : base(metadata, thing)
  {

  }

  public override void Perform()
  {
    throw new NotImplementedException();
  }
}

【讨论】:

  • 感谢您为帮助我所做的努力以及您宝贵的时间和见解
  • 你认为在元数据类的情况下在内部类中使用公共构造函数有意义吗?只是想学习一些好的做法:)
  • @ILoveStackoverflow - 在internal 类中,publicinternal 成员的含义几乎相同。我通常会默认将此类成员标记为public,尽管现实情况是它们实际上只是internal
  • 在我的项目类库的 Advance Build 设置中,我已经选择了“c# major latest version(default)”,但仍然出现错误 feature private protected is not available in c# 7.0
  • @ILoveStackoverflow - 我有点说错了,它是 7.2 的功能(如链接文档中所示),因此您需要移至“最新的次要”或至少 7.2。
猜你喜欢
  • 2019-08-27
  • 2013-11-13
  • 2013-07-25
  • 1970-01-01
  • 2014-08-29
  • 2012-08-18
  • 2011-04-02
  • 2015-08-12
相关资源
最近更新 更多