Подтвердить что ты не робот

Аргументы типа для метода не могут быть выведены из использования

Возможно, я перегружен работой, но это не компиляция (CS0411). Почему?

interface ISignatur<T>
{
    Type Type { get; }
}

interface IAccess<S, T> where S : ISignatur<T>
{
    S Signature { get; }    
    T Value { get; set; }
}

class Signatur : ISignatur<bool>
{
    public Type Type
    {
        get { return typeof(bool); }
    }
}

class ServiceGate
{
    public IAccess<S, T> Get<S, T>(S sig) where S : ISignatur<T>
    {
        throw new NotImplementedException();
    }
}

static class Test
{
    static void Main()
    {
        ServiceGate service = new ServiceGate();
        var access = service.Get(new Signatur()); // CS4011 error
    }
}

Любая идея, почему бы и нет? Или как решить?

4b9b3361

Ответ 1

Get<S, T> принимает два аргумента типа. Когда вы вызываете service.Get(new Signatur());, как компилятор знает, что такое T? Вам придется передать его явно или изменить что-то еще о ваших иерархиях типов. Передача этого явно будет выглядеть так:

service.Get<Signatur, bool>(new Signatur());

Ответ 2

Ответ Кирка прямо сейчас. Как правило, вам не удастся получить вывод типа, если ваша подпись метода имеет меньше типов параметров, чем у нее есть общие параметры типа.

В вашем конкретном случае кажется, что вы можете перенести параметр типа T на уровень класса, а затем получить вывод типа по методу Get:

class ServiceGate<T>
{
    public IAccess<S, T> Get<S>(S sig) where S : ISignatur<T>
    {
        throw new NotImplementedException();
    }
}

Затем код, который вы отправили с ошибкой CS0411, можно переписать как:

static void Main()
{
    // Notice: a bit more cumbersome to write here...
    ServiceGate<SomeType> service = new ServiceGate<SomeType>();

    // ...but at least you get type inference here.
    IAccess<Signatur, SomeType> access = service.Get(new Signatur());
}

Ответ 3

Теперь моя цель состояла в том, чтобы иметь одну пару с базовым типом и определением типа (Требование A). Для определения типа я хочу использовать наследование (Требование B). Использование должно быть возможным, без очевидных знаний по базовому типу (Требование C).

Теперь, когда я знаю, что ограничения gernic не используются для решения типичного типа возврата, я немного экспериментировал:

Ok let introducte Get2:

class ServiceGate
{
    public IAccess<C, T> Get1<C, T>(C control) where C : ISignatur<T>
    {
        throw new NotImplementedException();
    }

    public IAccess<ISignatur<T>, T> Get2<T>(ISignatur<T> control)
    {
        throw new NotImplementedException();
    }
}

class Test
{
    static void Main()
    {
        ServiceGate service = new ServiceGate();
        //var bla1 = service.Get1(new Signatur()); // CS0411
        var bla = service.Get2(new Signatur()); // Works
    }
}

Хорошо, но это решение не достигает требования B.

Следующая попытка:

class ServiceGate
{
    public IAccess<C, T> Get3<C, T>(C control, ISignatur<T> iControl) where C : ISignatur<T>
    {
        throw new NotImplementedException();
    }

}

class Test
{
    static void Main()
    {
        ServiceGate service = new ServiceGate();
        //var bla1 = service.Get1(new Signatur()); // CS0411
        var bla = service.Get2(new Signatur()); // Works
        var c = new Signatur();
        var bla3 = service.Get3(c, c); // Works!! 
    }
}

Ницца! Теперь компилятор может вывести общие типы возвращаемых данных. Но мне это не нравится. Другая попытка:

class IC<A, B>
{
    public IC(A a, B b)
    {
        Value1 = a;
        Value2 = b;
    }

    public A Value1 { get; set; }

    public B Value2 { get; set; }
}

class Signatur : ISignatur<bool>
{
    public string Test { get; set; }

    public IC<Signatur, ISignatur<bool>> Get()
    {
        return new IC<Signatur, ISignatur<bool>>(this, this);
    }
}

class ServiceGate
{
    public IAccess<C, T> Get4<C, T>(IC<C, ISignatur<T>> control) where C : ISignatur<T>
    {
        throw new NotImplementedException();
    }
}

class Test
{
    static void Main()
    {
        ServiceGate service = new ServiceGate();
        //var bla1 = service.Get1(new Signatur()); // CS0411
        var bla = service.Get2(new Signatur()); // Works
        var c = new Signatur();
        var bla3 = service.Get3(c, c); // Works!!
        var bla4 = service.Get4((new Signatur()).Get()); // Better...
    }
}

Моим окончательным решением будет иметь что-то вроде ISignature<B, C>, где B - базовый тип, а C - определение...

Ответ 4

Как я уже упоминал в своем комментарии, я думаю, причина в том, что это не работает, потому что компилятор не может вывести типы, основанные на общих ограничениях.

Ниже приведена альтернативная реализация, которая будет компилироваться. Я переработал интерфейс IAccess, чтобы иметь только параметр типа T.

interface ISignatur<T>
{
    Type Type { get; }
}

interface IAccess<T>
{
    ISignatur<T> Signature { get; }
    T Value { get; set; }
}

class Signatur : ISignatur<bool>
{
    public Type Type
    {
        get { return typeof(bool); }
    }
}

class ServiceGate
{
    public IAccess<T> Get<T>(ISignatur<T> sig)
    {
        throw new NotImplementedException();
    }
}

static class Test
{
    static void Main()
    {
        ServiceGate service = new ServiceGate();
        var access = service.Get(new Signatur());
    }
}

Ответ 5

Я хотел сделать простой и понятный пример

если вы вызовете такой метод, ваш клиент не будет знать тип возвращаемого значения

var interestPoints = Mediator.Handle(new InterestPointTypeRequest
            {
                LanguageCode = request.LanguageCode,
                AgentId = request.AgentId,
                InterestPointId = request.InterestPointId,
            });

Тогда вы должны сказать компилятору, что я знаю, что тип возвращаемого значения - List<InterestPointTypeMap>

var interestPoints  = Mediator.Handle<List<InterestPointTypeMap>>(new InterestPointTypeRequest
            {
                LanguageCode = request.LanguageCode,
                AgentId = request.AgentId,
                InterestPointId = request.InterestPointId,
                InterestPointTypeId = request.InterestPointTypeId
            });

компилятор больше не будет злиться на вас за то, что вы знаете тип возвращаемого значения