简体   繁体   中英

Generics using public interfaces and internal type parameters

I have the following situation:

// A public interface of some kind   
public interface IMyInterface {   
    int Something { get; set; }   
}   

// An internal class that implements the public interface.   
// Despite the internal/public mismatch, this works.   
internal class MyInternalConcrete : IMyInterface {   
    public int Something { get; set; }   
}   

// A generic class with an interface-restricted type parameter.
// Note that the constraint on T uses the *public* interface.
// The instance is *never* exposed as a public, or even protected member.
public class MyClass<T> where T : IMyInterface, new() {   
    T myInterfaceInstance;   

    public MyClass() {   
        myInterfaceInstance = new T();   
    }   
}   

// Attempting to implement concrete class... Inconsistent Accessibility Error!   
public class MySpecificClass : MyClass<MyInternalConcrete>   
{   
}  

When trying to implement MySpecificClass, I get the error:

Inconsistent accessibility: base class 'App1.MyClass' is less accessible than class 'App1.MySpecificT'

Where it gets weird is that MyInternalConcrete, despite being internal , can still implement a public interface. And since it implements the interface, then it should be useable as a type parameter for MyClass - because T is constrained on the public interface and not the internal class.

I would understand it failing if MyClass exposed T, just as it would fail if we weren't using generics:

public class MyClass<T> where T : IMyInterface, new() {      
    T myInterfaceInstance;      

    public MyClass() {      
        myInterfaceInstance = new T();      
    }      

    // This will fail with an internal T - inconsistent accessibility!    
    public T Instance {      
        get { return myInterfaceInstance; }      
    }      
}

And same as above, but without generics:

public class MyNonGenericClass {   
    MyInternalConcrete myInterfaceInstance;   

    public MyNonGenericClass() {   
        myInterfaceInstance = new MyInternalConcrete();   
    }   

    // This will fail - inconsistent accessibility! 
    // but removing it works, since the private instance is never exposed.   
    public MyInternalConcrete Instance {   
        get { return myInterfaceInstance; }   
    }   
}  

Is this a limitation of the C# generics or am I simply misunderstanding something fundamental about how generics work?

I also posted this thread on MSDN , but I'm being dismissed as not knowing what I'm talking about. Is my concern even valid?

According to this article on C# generics

"The visibility of a generic type is the intersection of the generic type with the visibility of the parameter types . If the visibility of all the C, T1, T2 and T3 types is set to public, then the visibility of C is also public; but if the visibility of only one of these types is private, then the visibility of C is private."

So whilst your example could be possible, it doesn't fit with the rules as defined.

For a more definitive source see section 25.5.5 (page 399) of the C# spec .

A constructed type C is accessible when all of its components C, T1, ..., TN are accessible. More precisely, the accessibility domain for a constructed type is the intersection of the accessibility domain of the unbound generic type and the accessibility domains of the type arguments.

This constraint you are facing makes sense for the following reason.

C# is strongly typed so...

To be able to reference the MySpecificClass outside the scope of the assembly it is defined in you must know its parameter types in order to generate a strong type reference to its instance; but an separate assembly than the internal definition does not know about MyInternalConcrete.

Thus the following wont work if in a separate assembly:

MyClass<MyInternalConcrete> myInstance = new MySpecificClass();

Here the separate assembly doesn't know of MyInternalConcrete, so how can you define a variable as such.

如果允许的话,您可以将MyClass传递出程序集,突然之间,另一个程序集可以访问它不应该访问的内容-MyInternalConcrete!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM