В соответствии с комментарием-ответом @ Damien_The_Unbeliever, тип-вывод C# не поддерживает частичный вывод - либо все параметры (и тип возврата, если применимо) должны быть выведены из вызова -site - или вы должны вручную указать все параметры типа.
Хотя во многих случаях есть обходные пути:
Stati c методы с возможными логическими аргументами типа:
Если у вас есть фабричный метод stati c в обобщенном классе c, вы можете переместить метод в класс stati c и переместить аргумент типа родительского класса в метод, если он может быть выведен:
public class Foo<T>
{
public static Bar CreateBar( T item )
{
// ...
}
}
Пример call-сайта:
Bar bar = Foo<Coffee>.Bar( starbucks );
Альтернатива:
public static class Foo
{
public public static Bar CreateBar<T>( T item )
{
// ...
}
}
Пример call-сайта:
Bar bar = Foo.Bar( starbucks ); // voila, type-inference!
Методы с не- аргументы заразного типа:
Методы с аргументами типа, которые не могут быть выведены из сайта вызова, могут быть преобразованы в новые обобщенные c методы с частичным применением параметров, например:
Рассмотрим :
class Foo<TClass>
{
public TReturn DoSomething<TParam,TUnused,TReturn>( TParam p )
{
// ...
}
}
E xample call-site:
Violin stradivarius = ...
Woodwind flute = new Foo<Orchestra>().DoSomething<Violin,Percussion,Woodwind>( stradivarius ); // `Violin` was required and couldn't be inferred.
Однако мы можем заключить этот метод DoSomething
в другой вызов метода, где некоторые аргументы типа уже предоставлены родительским контекстом , таким как аргументы типа родительского класса или как аргументы типа для методов класса 'stati c только с типами для параметров, которые могут быть выведены.
Таким образом, вы можете сортировать частично применить эти общие c типы с Func<>
, например так:
class PAReturn<TReturn>
{
public static TReturn Invoke( Func<TReturn> func ) => func();
public static TReturn Invoke<T0>( Func<T0,TReturn> func, T0 arg ) => func( arg );
public static TReturn Invoke<T0,T1>( Func<T0,T1,TReturn> func, T0 arg, T1 arg1 ) => func( arg, arg1 );
public static TReturn Invoke<T0,T1,T2>( Func<T0,T1,T2,TReturn> func, T0 arg, T1 arg1, T2 arg2 ) => func( arg, arg1, arg2 );
// etc
}
class PAReturn<TReturn,T0>
{
public static TReturn Invoke( Func<T0,TReturn> func, T0 arg ) => func( arg );
public static TReturn Invoke<T1>(Func<T0, T1, TReturn> func, T0 arg, T1 arg1) => func(arg, arg1);
public static TReturn Invoke<T1,T2>(Func<T0, T1, T2, TReturn> func, T0 arg, T1 arg1, T2 arg2) => func( arg, arg1, arg2 );
}
Пример call-сайта:
Violin stradivarius = ...
Woodwind flute = PartialAply<Percussion,Woodwind>( new Foo<Orchestra>().DoSomething )( stradivarius ); // Observe that `Violin` was inferred.
Неиспользуемые параметры:
Еще один прием Воспользуйтесь преимуществами того, как вывод типов лучше всего работает для параметров, создавая перегрузки с неиспользуемыми out
параметрами, которые можно указать с помощью способности C# 7.0 делать объявления внутри аргументов out
параметров в call-сайтах и как переменные / параметры именуются _
отбрасываются:
class Foo<A>
{
// Original method:
public B GetSomething<B,C,D>( C paramC )
{
// ...
}
}
Пример call-сайта:
Cat bagheera = ...
Mouse m = new Foo<Flea>().GetSomething<Mouse,Cat,Dog>( bagheera ); // `Cat` was not inferred.
Примерно так:
partial class Foo<A>
{
// Inference helper overload:
public B GetSomething<B,C,D>( out B b, out D d, C c)
{
return this.GetSomething<B,C,D>( c );
}
}
Пример call-сайта:
Cat bagheera = ...
Mouse m = new Foo<Flea>().GetSomething( out Mouse _, out Dog _, bagheera ); // `Cat` was inferred.
Комбинировано:
Это может быть объединено с новым дель Например, определения с параметрами out
для параметров типа, не подлежащих замене (потому что мы не можем использовать Func<>
, потому что в нем нет параметров out
):
delegate TReturn PAFunc<TReturn>( out Return _ );
delegate TReturn PAFunc<T0,TReturn>( out Return _, T0 arg0 );
delegate TReturn PAFunc<T0,T1,TReturn>( out Return _, T0 arg0, T1 arg1 );
delegate TReturn PAFunc<T0,T1,N0,TReturn>( out Return _, out N0 _, T0 arg0 ); // `N0` refers to which one is non-inferrable
// etc...