在 C# 中是否可以使用内部 AND 受保护成员?

Is an internal AND protected member possible in C#?

考虑以下 classes:

public class Vehicle { ... }
public class Coverage { ... }

public class VehicleList : IEnumerable<Vehicle> { ... }
public class CoverageList : IEnumerable<Coverage> { ... }

public abstract class Quote
{
    protected VehicleList vehicles;
    protected CoverageList coverages;

    internal Quote() { ... }

    public IReadOnlyCollection<Vehicle> Vehicles
    {
        get { return this.vehicles.AsReadOnly(); }
    }
    public IReadOnlyCollection<Coverage> Coverages
    {
        get { return this.coverages.AsReadOnly(); }
    }

    ...
}

public sealed class OhQuote : Quote
{
    //needs to access protected fields
    ...
}
public sealed class InQuote : Quote { ... }
public sealed class MiQuote : Quote { ... }

Quote 完全封装了 VehicleListCoverageList 的功能,所以我想将那些 class 标记为 internal。问题是它们是 public class 的 protected 字段的类型。如果我将这些字段标记为 protected internal,那么它们就是 protectedinternal。我真正需要的是它们是 protectedinternalprotected 在程序集内优先)。您可以看到 Quote(它有一个 internal 构造函数)和它的子 class(它们是 sealed)都不能扩展到程序集之外。我已经想出如何使用 public 接口实现所需的功能,但想确保没有更简洁的方法。

尽管 .NET 运行时支持此概念 ("FamilyAndAssembly"),但 C# 目前不支持。

这是以 private protected 访问修饰符的形式针对 C# 6.0 提出的,但该功能已被删除。

更新: private protected 已添加到 C# 7.2

作为附录: 如果你不想使用接口并且 - 如你所见 - 没有 C# 支持来实现该目标,记住:你总是可以使用 反射做那种很奇怪的事情。

您可以将字段设置为 private 并使用反射,您可以从任何您想要的地方分配新值,确保来自同一程序集中的派生 类。

我怀疑您派生的 classes 是否需要直接访问 Quote 的字段。

I am asking if there is a way to achieve the desired functionality without using public interfaces.

我认为您可以安全地将字段上的修饰符更改为 private 并让派生的 classes 通过 [=13] 间接 操作字段 =] 方法在您的 Quote 基础 class 中定义。不需要额外的 public 接口。

下面是它的外观示例:

public class Vehicle {}
public class Coverage {}

// Set these as "internal" as you were hoping for...
internal class VehicleList : IEnumerable<Vehicle>
{
    public void Foo() {}
}

internal class CoverageList : IEnumerable<Coverage>
{
    public void Bar() {}
}

public abstract class Quote
{
    // Mark these as "private"
    private VehicleList vehicles;
    private CoverageList coverages;

    internal Quote() {}

    public IReadOnlyCollection<Vehicle> Vehicles
    {
        get { return this.vehicles.AsReadOnly(); }
    }
    public IReadOnlyCollection<Coverage> Coverages
    {
        get { return this.coverages.AsReadOnly(); }
    }

    // Add protected methods to manipulate the private fields.
    protected void PerformFooOnVehicles()
    {
        this.vehicles.Foo();
    }

    protected void PerformBarOnCoverages()
    {
        this.coverages.Bar();
    }

}

public sealed class OhQuote : Quote
{
    // We now have indirect access to Quote's private fields.
    public void Baz()
    {
        this.PerformBarOnCoverages();
        this.PerformFooOnVehicles();
    }
}
public sealed class InQuote : Quote {}
public sealed class MiQuote : Quote {}

此替代方案实现了 间接 VehicleListCoverageList 暴露给派生 [=32] 的目标=]属于同一个程序集的 es。