internal interface *less* accessible than an internal protected constructor? - c#

I have an interface and an abstract base class defined in the same assembly:
IFoo.cs:
internal interface IFoo { ... }
Base.cs:
public abstract class Base
{
internal protected Base(IFoo foo) { ... }
}
This generates the following compiler error:
CS0051: Inconsistent accessibility: parameter type 'IFoo' is less
accessible than method 'Base.Base(IFoo)'
If I make the Base class constructor internal-only, the error goes away. Since the class is abstract, maybe adding protected to the accessibility doesn't accomplish anything...
Still, I don't understand the error. MSDN defines 'protected internal' as
"Access is limited to the current assembly or types derived from the
containing class"
How is the internal interface IFoo less accessible than an internal protected constructor?

This MSDN page defined 'protected internal' as (emphasis from original):
The protected internal accessibility level means protected OR
internal, not protected AND internal. In other words, a protected
internal member can be accessed from any class in the same assembly,
including derived classes. To limit accessibility to only derived
classes in the same assembly, declare the class itself internal, and
declare its members as protected.
So in other words, types from outside the current assembly that derive from Base would have access to Base(IFoo foo) but they wouldn't have access to IFoo, since it is internal. Thus the error.

Related

abstract, virtual and sealed methods in interfaces of C#-8

The following interface has no errors in a .Net Core Console application with C#-8.0
interface I
{
public abstract void f();
public virtual void g() => Console.WriteLine("g");
public sealed void h() => Console.WriteLine("h");
}
abstract prevents adding a definition in interface. virtual and sealed necessitate a definition in interface. sealed prevents an implementation of h in derived classes.
Do abstract, virtual and sealed, when used in interfaces, have any other meaning or applications in current implemented version of C# - 8? How and when should they be used in interfaces?
This is from the proposal:
The syntax for an interface is relaxed to permit modifiers on its
members. The following are permitted: private, protected, internal,
public, virtual, abstract, sealed, static, extern, and partial.
An interface member whose declaration includes a body is a virtual
member unless the sealed or private modifier is used. The virtual
modifier may be used on a function member that would otherwise be
implicitly virtual. Similarly, although abstract is the default on
interface members without bodies, that modifier may be given
explicitly. A non-virtual member may be declared using the sealed
keyword.
It is an error for a private or sealed function member of an interface
to have no body. A private function member may not have the modifier
sealed.

How to prevent an abstract class with public derived classes from being inherited in other assemblies?

I want to write something like the following:
internal class InternalData
{
}
public class PublicData
{
}
abstract internal class Base {
internal Base() { }
private static InternalData CreateInternalDataFromPublicData(PublicData publicData)
{
throw new NotImplementedException();
}
abstract protected void DoProcess(InternalData internalData);
public void Process(PublicData publicData)
{
InternalData internalData = CreateInternalDataFromPublicData(publicData);
DoProcess(internalData);
}
}
public sealed class Derived : Base
{
protected override void DoProcess(InternalData internalData)
{
throw new NotImplementedException();
}
}
That is, Base contains some internal logic and is not intended to be inherited by classes outside of my assembly; and Derived is accessible from the outside.
InternalData also contains some internal logic and, as it would (and should) never be used from the outside, i also want to make it internal.
Of course the code above won't compile as the Base should not be less accessible than Derived. I can set the Base to be public, that's fine, but it leads to another problem.
If Base is public, then there could possibly be some ExternalDerived : Base in some other assembly. But Base.DoProcess accepts an InternalData as its argument, so that ExternalDerived cannot implement it (as it doesn't know about the InternalData).
Internal parameterless Base constructor prevents creation of any ExternalDerived instances, and thus nobody will implement ExternalDerived.DoProcess and no InternalData public exposure is needed, but the compiler doesn't know it.
How can i rewrite the code above so that there will be an abstract DoProcess(InternalData) method and so that InternalData class will be internal?
Since C# 7.2 there is private protected access modifier, which means "available only to derived classes in the same assembly".
In other words, it must meet conditions for both internal AND protected, unlike protected internal which applies to internal OR protected.
You can mark the base class' constructor as private protected, effectively preventing inheritance of that class through this constructor outside the assembly while still allowing inheritance within that assembly (and the assembly's friends).
So, a class like this:
public abstract BaseClass
{
private protected BaseClass() {}
}
is effectively sealed outside the assembly, while still inheritable within the assembly.
To make InternalData internal, DoProcess must be private or internal
(or InternalAndProtected, but C# doesn't support this CLR feature). It can't be protected or protected internal.
internal abstract DoProcess(InternalData internalData);
I'd probably also add an internal abstract void DoNotInheritFromThisClassInAnOutsideAssembly() member. That prevents anybody outside the assembly from inheriting from your class, because they can't implement that member and they get a reasonable compiler error. But you can't make the Base class itself internal.
I'd consider refactoring the code, so that you have no common base class. Probably by using some internal interfaces and composition.
It smells like you should use composition instead of inheritance. sorry, this is a very vague answer. I'm thinking more about this now..
The base type must be accessible, because otherwise, it becomes impossible to figure out its base. Your Base derives directly from System.Object, but how does a user of Derived know that? How does it know that Base doesn't derive from another public type, and that type's members should be made available?
If you mark everything in Base internal, except for the class itself, you've already prevented other assemblies from doing anything useful with it. In other words, if you make DoProcess internal, you can then prevent InternalData from becoming public.
Yes, admittedly this allows for bugs in your own assembly, if other classes try to call DoProcess. Unfortunately, there is no "accessible from derived classes in the same assembly" access modifier, only "accessible from derived classes", "accessible from the same assembly" and "accessible from derived classes and accessible from the same assembly". (Actually, .NET does support it, but C# doesn't.)
Set Base to be public.
public abstract class Base {...
Change Base.DoProcess:
protected virtual void DoProcess<T>(T internalData)
{
if (!(internalData is InternalData))
{
throw new ArgumentOutOfRangeException("internalData");
}
}
Change Derived.DoProcess:
protected override void DoProcess<T>(T internalData)
{
base.DoProcess(internalData);
// Other operations
}
It is actually quite straight forward. You just require that a deriving class implement an abstract internal method. Classes outside the library won't be able to implement the abstract method, and thus fail at compile time.
Your example, minimized to just the essentials:
abstract internal class Base {
internal protected abstract void DoProcess();
public void Process() {
DoProcess();
}
}
public sealed class Derived : Base {
internal protected override void DoProcess() {
throw new NotImplementedException();
}
}

Why can't I have a public class that inherits from an internal class?

I do not understand the accessibility limitations exhibited below
public abstract class Base { }
internal class Common : Base { }
public class Instance : Common { }
This won't compile.
Inconsistent accessibility: base class 'Common' is less accessible than class 'Instance'
I can accomplish what I wanted with public abstract class Common but why can't I simply not expose the name at all?
Edit: What I'm asking is WHY it works this way! Everyone is answering with what the rules are, not explaining why the rules are that way.
Inheritors of a class cannot widen the scope of accessibility of the base class.
public: Access not limited
internal: Access limited to this program
Once limited to the program, all inheritors of a, internal class must remain internal or assume lesser accessibility (protected internal or private).
Per the C# specification, section §3.5.4 Accessibility constraints:
The parameter types of an instance constructor must be at least as
accessible as the instance constructor itself.
In the example
class A {...}
public class B: A {...}
the B class results in a compile-time error because A is not at least
as accessible as B.
Also:
The direct base class of a class type must be at least as accessible
as the class type itself (§3.5.2). For example, it is a compile-time
error for a public class to derive from a private or internal class.
If you are trying to create a Common class with functionality you prefer not to make accessible to external code, you should prefer composition over inheritance. For example:
public abstract class Base
{
...
}
internal class Common : Base
{
...
}
public class Instance
{
internal Instance(Common common)
{
...
}
...
}
It's a matter of how visible the code is to other assemblies. By making Common internal you're limiting access to Common to its assembly whereas by making Instance public you're making Instance accessible to any referencing assembly. If a referencing assembly can't access a type's base class how could it access any members inherited from that base class?
If Common contained a property, lets say Foo:
public string Foo { get; set; }
than the Instance class would automatically expose that property. You can think of it this way:
public void Test()
{
Common myInstance = new Instance();
System.Console.WriteLine(myInstance.Foo);
}
Since Instance needs to expose everything Common has, the access modifier on the base class cannot be less exposed.
You could, however, create the property Foo as internal to accomplish much the same.

c# abstract methods: internally public and virtual?

Are abstract methods internally public and virtual in c#?
All methods are, by default, private and if an abstract method is private, it will not be available to derived class, yielding the error "virtual or abstract members cannot be private"
I think you are asking a different question than most people think (in other words it seems like you understand what abstract means).
You cannot declare a private abstract method - the compiler issues an error. Both of these classes will not compile:
class Foo
{
private abstract void Bar();
}
class Baz
{
// This one is implicitly private - just like any other
// method declared without an access modifier
abstract void Bah();
}
The compiler is preventing you from declaring a useless method since a private abstract member cannot be used in a derived class and has no implementation (and therefore no use) to the declaring class.
It is important to note that the default access modifier applied to an abstract member by the compiler (if you do not specify one yourself) is still private just like it would be if the method was not abstract.
Abstract is just a way to say: "I am here, but no one has told me what I'm going to do yet." And since no one has implemented that member yet someone must do that. To do that you have to inherit that class, and override that member.
To be able to override something it has to be declared either abstract or virtual, and must at least be accessible to the inheritor, i.e. must be marked protected, internal or public.
Abstract methods cannot be private and are virtual. They must be at least protected.
By virtue of Jon Skeet's argument here (What are the Default Access Modifiers in C#?)
The default access for everything in C# is "the most restricted access you could declare for that member"
It must be "protected"
As pointed out by Pieter default is always private, so:
abstract class Foo
{
abstract void Bar();
}
Gives compiler error
virtual or abstract members cannot be private

Does a types accessibility depend on the file it's contained in?

If I declare an interface, or a type as private in one file, is it private to that file or the namespace?
The compiler generates an error for File2: 'Error 14 Inconsistent accessibility: parameter type 'DIDemo1.IImageRepository' is less accessible than method 'DIDemo1.ImageGetter.ImageGetter(DIDemo1.IImageRepository)'
What I don't understand is that MyClass can use the interface but ImageGetter class cannot.
File1:
namespace DIDemo1 {
interface IImageRepository {
Image[] GetImages();
}
public class MyClass : IImageRepository {
#region IImageRepository Members
public Image[] GetImages() {
return new Image[] { };
}
#endregion
}
}
File2:
namespace DIDemo1 {
public class ImageGetter {
IImageRepository _repo;
public ImageGetter(IImageRepository repository) {
_repo = repository;
}
public Image[] GetImages() {
return _repo.GetImages();
}
}
}
Since you did not specify an access modifier for your interface, it defaults to internal, which is lower than public. That means only code in the same assembly are aware of its existence.
A public class can implement an internal interface, because other code inside that same assembly would see your class with the interface, and code outside would simply see the public class, with no interface.
However, in File2, you are making an internal interface part of that class' public contract - that is, your class is public, which means any code can see it, but in order to use it they must also be able to understand the types in the constructor. Since one of the types required in the constructor is internal, external code cannot understand it, and this contract is impossible to fulfill.
What I don't understand is that MyClass can use the interface but ImageGetter class cannot.
ImageGetter can use the interface, it just can't present it in one of its method signatures which are more accessible. Likewise if MyClass tried to use it in one of its method signatures you'd get the same error. Read below.
Top level interfaces, structs, and classes default to internal access. To fix your problem put public before your interface declaration.
internal types in C# are accessible only within the same assembly.
You can't use a more restrictive access modifier in a less restrictive signature for obvious reasons. (How could someone who can't access the more restrictive type call the function for example?)
No, which file the code is in is irrelevant. The interface is private to the namespace, not the file.
The error message is not because the ImageGetter class can't reach the interface, it's because the class can't be used from outside the namespace.
The difference lies in how you use the interface. The class MyClass only implements the interface, so you can still use the class even if you can't use the interface. The constructor in the ImageGetter class requires a reference to the interface, so you can't use that class without also having access to the interface.
Interfaces and classes default to internal accessibility (because there is no concept of a class being private inside a namespace). The error explains what happens there - IImageRepository is less accessible (it is internal) than ImageGetter constructor, which exposes IImageRepository as a parameter.
Basically a public method on ImageGetter exposes a type that is internal. This is not allowed in C#.

Categories

Resources