Add public
/internal
/private
visibility markers on inheritance, to stop contract propagation
#7901
-
Hello, This example: public abstract class MyAbstractExposedClass
{}
interface IDataYesExposedField
{ string? Yes { get; set; } }
interface IDataNoExposedField
{ string? No { get;set; } }
interface ILibraryApiFields
{
string? Yes { get; set; }
string? No { get;set; }
}
public class LibraryExportData : MyAbstractExposedClass, IDataYesExposedField, IDataNoExposedField, ILibraryApiFields
{
public string? Yes { get; set; }
public string? No { get; set; }
} Api consumers may have no use for specific Something like that: //...
public class LibraryExportData : internal MyAbstractExposedClass, private IDataYesExposedField, private IDataNoExposedField, ILibraryApiFields
{
public string? Yes { get; set; }
public string? No { get; set; }
} Default contract visibility being implicitly Defined goalI need it when API objects are from a provider, then served to another customer, but I don't want to expose that level of contractness, without an object remap for privacy concerns. Counterpoints
Please express your concerns below, counterpoints are welcome! |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 13 replies
-
I could see an attribute in conjunction with a Roslyn Analyzer can be used for this. Nowhere near as clean, but it can be done today :) [InternalInterface<IDataYesExposedField>]
[InternalInterface<IDataNoExposedField>]
[InternalInheritance<MyAbstractExposedClass>]
public class LibraryExportData
{
public string? Yes { get; set; }
public string? No { get; set; }
} |
Beta Was this translation helpful? Give feedback.
-
IIRC it was an intentional design decision that the contract of a subclass cannot be narrower than the contract of its base class. I don't believe the runtime even has a concept of narrowing implementation. You could use explicit implementation to at least hide the members, but the type will always implement the interface and could be cast to the interface to allow invoking those members. |
Beta Was this translation helpful? Give feedback.
-
I'd expect access modifiers to be respected even at the consumption level which immediately makes public interface ISample { ... }
public class FooBar : private ISample { ... }
public void ProcessSample(ISample sample) { ... }
var foobar = new FooBar(...);
// Argument type 'FooBar' is not assignable to parameter type 'ISample'.
ProcessSample(foobar);
You did make a point that I'm sure many can empathize with:
However, in this case, I think if you want that level of control then mapping to another type is the best course of action to not violate consumer expectations. I agree with @HaloFour here in that I'd expect a derived type to contain everything from its parent at a minimum. |
Beta Was this translation helpful? Give feedback.
-
internal class MyAbstractExposedClass
{}
internal interface IDataYesExposedField
{ string? Yes { get; set; } }
internal interface IDataNoExposedField
{ string? No { get;set; } }
public interface ILibraryApiFields
{
string? Yes { get; set; }
string? No { get;set; }
}
public class LibraryExportData : IDataYesExposedField, IDataNoExposedField, ILibraryApiFields
{
MyAbstractExposedClass _compositionField;
public string? Yes { get; set; }
public string? No { get; set; }
} |
Beta Was this translation helpful? Give feedback.
-
As nobody stated, I can already do that with # directives: //#define LIMITED_INTERFACES //Uncomment to activate limited-scope interfaces
System.Console.WriteLine(((IDataYesExposedField)new LibraryExportData()).Yes);
public abstract class MyAbstractExposedClass
{}
interface IDataYesExposedField
{ string? Yes { get; set; } }
interface IDataNoExposedField
{ string? No { get;set; } }
interface ILibraryApiFields
{
string? Yes { get; set; }
string? No { get;set; }
}
public class LibraryExportData :
#if LIMITED_INTERFACES
MyAbstractExposedClass, IDataYesExposedField, IDataNoExposedField,
#endif
ILibraryApiFields
{
public string? Yes { get; set; }
public string? No { get; set; }
} Thanks for your attention. |
Beta Was this translation helpful? Give feedback.
As nobody stated, I can already do that with # directives:
…