Использование общего ограничения и ограничения интерфейса: можете ли вы объяснить ошибку в этом коде?

Я получаю следующую ошибку:

Ошибка CS0311 Тип «ConsoleApp1.Diesel» нельзя использовать в качестве параметра типа «T» в универсальном типе или методе «Car». Нет неявного преобразования ссылок из ConsoleApp1.Diesel в ConsoleApp1.Fuel. ConsoleApp1

Почему я не могу ограничиться дженериком и интерфейсом?

using System;

namespace ConsoleApp1
{
    public interface IVehicle
    {
        void StartEngine();
    }

    public abstract class Fuel
    { }

    public class Diesel : Fuel
    { }

    public class Engine<F>
    {    
        public void Start()
        { }

        private void TransformFuelToEnergy()
        { }
    }    

    public class Car<T> where T : Fuel, IVehicle
    {
        private Engine<T> engine;

        public void Start()
        {
            engine.Start();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Car<Diesel> myCar;    
        }
    }
}

c#
person olleo    schedule 30.10.2018    source источник
comment
это потому, что ваше дизельное топливо НЕ получено из топлива.   -  person daremachine    schedule 30.10.2018
comment
Это не имеет особого смысла. При этом Diesel не происходит от Fuel.   -  person JuanR    schedule 30.10.2018
comment
@daremachine: да, я знаю, это потому, что мне не разрешено публиковать настоящий код. Я забыл о наследовании, но это не решает ошибку.   -  person olleo    schedule 31.10.2018
comment
@olleo: прочитай мой ответ.   -  person JuanR    schedule 31.10.2018


Ответы (3)


Прежде всего, ваш класс Diesel должен наследоваться от Fuel:

public class Diesel : Fuel { }

Затем ваш Engine<F> должен иметь ограничение, где F — это некоторый тип Fuel:

public class Engine<F> where F : Fuel
{
    public void Start()
    { }

    private void TransformFuelToEnergy()
    { }
}

Наконец, ваш Car<T> должен реализовать IVehicle и включать ограничение для Fuel:

public class Car<T> : IVehicle where T : Fuel
{
    private Engine<T> engine = new Engine<T>();

    public void StartEngine()
    {
        engine.Start();
    }
}

Затем ваш класс Car<T> предоставляет метод StartEngine для удовлетворения интерфейса, который работает с частной переменной Engine<T> (которую необходимо инициализировать).

person JuanR    schedule 30.10.2018

Вы ограничили класс Car<T> оператором where, говорящим, что T должен быть либо Fuel, либо IVehicle. Класс Diesel не является ни Fuel, ни IVehicle, что приводит к ошибке вашего компилятора.

Я думаю, вы хотите, чтобы Diesel было Fuel, и в этом случае вы можете определить его следующим образом:

public class Diesel : Fuel { }

Что должно заставить ваш код компилироваться просто отлично.

person GTHvidsten    schedule 30.10.2018
comment
Это не наследство. - person olleo; 31.10.2018
comment
Да, это. Ответ, который вы приняли, даже имеет то же значение, что и я (он просто идет немного дальше исходного вопроса и немного исправляет ваш код). - person GTHvidsten; 31.10.2018

Когда вы используете

где T : топливо, транспортное средство

Он требует, чтобы класс, который вы передаете, реализовывался как из абстрактного класса, так и из интерфейса.

public class Diesel : Fuel, IVehicle
{
    public void StartEngine()
    {
        throw new NotImplementedException();
    }
}
person Ryan Schlueter    schedule 30.10.2018