Аргументы типа для метода не могут быть выведены из использования - PullRequest
48 голосов
/ 12 октября 2010

Может быть, я перегружен, но это не компилируется (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
    }
}

У кого-нибудь есть идеи, почему бы и нет? Или как решить?

Ответы [ 5 ]

64 голосов
/ 12 октября 2010

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

service.Get<Signatur, bool>(new Signatur());
11 голосов
/ 12 октября 2010

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

В вашем конкретном случае кажется, что вы могли бы возможно переместить параметр типа 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 голосов
/ 13 октября 2010

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

После того, как я теперь знаю, что генетические ограничения не используются для решения универсального возвращаемого типа, я немного поэкспериментировал:Хорошо, но это решение не достигает требования 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 - определение ...

0 голосов
/ 17 июня 2019

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

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

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

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

0 голосов
/ 12 октября 2010

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

Ниже приведена альтернативная реализация, которая будет компилироваться. Я изменил интерфейс 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());
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...