Обобщения с использованием открытых интерфейсов и параметров внутреннего типа - PullRequest
0 голосов
/ 31 января 2009

У меня следующая ситуация:

// 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>   
{   
}  

При попытке реализовать MySpecificClass выдается ошибка:

Непоследовательная доступность: базовый класс App1.MyClass менее доступен, чем класс App1.MySpecificT

Что странно, так это то, что MyInternalConcrete, несмотря на то, что внутренний , все еще может реализовывать открытый интерфейс. И поскольку он реализует интерфейс, то должен использоваться в качестве параметра типа для MyClass - поскольку T ограничен открытым интерфейсом, а не внутренним классом.

Я бы понял, что он потерпит неудачу, если MyClass выставит T, точно так же, как и если бы мы не использовали обобщенные значения:

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; }      
    }      
}

И то же, что и выше, но без генериков:

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; }   
    }   
}  

Это ограничение дженериков C # или я просто неправильно понимаю что-то фундаментальное о том, как работают дженерики?

Я также разместил эту ветку на MSDN , но меня увольняют как не знающей, о чем я говорю. Является ли мое беспокойство даже в силе?

Ответы [ 3 ]

7 голосов
/ 31 января 2009

Согласно этой статье на C # generics

"Видимость универсального типа пересечение универсального типа с видимостью параметра Типы . Если видимость всего С, Типы T1, T2 и T3 установлены как открытые, тогда видимость C равна также публично; но если видимость только один из этих типов является частным, тогда видимость C равна частный ".

Так что, хотя ваш пример возможен, он не соответствует определенным правилам.

Более точный источник см. В разделе 25.5.5 (стр. 399) спецификации C # .

Сконструированный тип С доступны, когда все его компоненты C, T1, ..., TN доступны. Больше точно, домен доступности для построенного типа является пересечение доступности домен несвязанного родового типа и домены доступности типа аргументы.

5 голосов
/ 31 января 2009

Это ограничение имеет смысл по следующей причине.

C # строго напечатан, поэтому ...

Чтобы иметь возможность ссылаться на MySpecificClass вне области сборки, в которой он определен, вы должны знать типы его параметров, чтобы генерировать надежную ссылку на тип для его экземпляра; но отдельная сборка, кроме внутреннего определения, не знает о MyInternalConcrete.

Таким образом, в отдельной сборке не будет работать следующее:

MyClass<MyInternalConcrete> myInstance = new MySpecificClass();

Здесь отдельная сборка не знает MyInternalConcrete, так как же вы можете определить переменную как таковую?

1 голос
/ 31 января 2009

Если бы это было разрешено, вы могли бы пропустить MyClass из сборки, и внезапно другая сборка получила доступ к тому, чего не должно было бы - MyInternalConcrete!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...