Почему я не могу использовать «как» с параметром универсального типа, который ограничен интерфейсом?

В приведенном ниже примере (только для демонстрационных целей), если T не ограничен классом, то это преобразование:

var ret = objectA as T;

.. вызовет следующую ошибку компиляции:

Параметр типа «T» нельзя использовать с оператором «as», поскольку он не имеет ни ограничения типа класса, ни ограничения «класса».

Я не могу понять, почему я не могу этого сделать. Поскольку я ограничил T интерфейсом IObject, компилятор должен знать, что T должен быть типом интерфейса, а операция as должна быть допустимой.

public interface IObject
{
    string Id { get; set; }
}
public class ObjectA : IObject
{
    public string Id { get; set; }
}
public class ObjectFactory
{
    public T CreateObject<T>(string id) where T : IObject
    {
        ObjectA objectA = new ObjectA();
        var x = objectA as IObject; // this is good
        var ret = objectA as T; // why this 'as' cannot compile?
        return ret;
    }
    public T CreateClassObject<T>(string id) where T : class, IObject
    {
        ObjectA objectA = new ObjectA();
        var ret = objectA as T; // if T is class, this 'as' can compile
        return ret;
    }
}

person ricky    schedule 05.01.2018    source источник


Ответы (1)


поскольку я ограничил T интерфейсом IObject, компилятор должен знать, что T должен быть интерфейсным типом, и операция as должна быть допустимой.

Нет, T не обязательно должен быть типом интерфейса. Это должен быть тип, реализующий интерфейс. Учитывать:

public struct Foo : IObject
{
    public string Id { get; set; }
}

Теперь, что вы ожидаете от CreateObject<Foo>("ff")?

С ограничением class на CreateObject этот вызов будет недействительным, поскольку Foo не является ссылочным типом — компилятор знает, что T является ссылочным типом, поэтому objectA as T в порядке.

person Jon Skeet    schedule 05.01.2018