Аргументы типа для метода не могут быть выведены из использования
Возможно, я перегружен работой, но это не компиляция (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
}
}
Любая идея, почему бы и нет? Или как решить?
Ответы
Ответ 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
});
компилятор больше не будет злиться на вас за то, что вы знаете тип возвращаемого значения