Здравствуйте, Ziaw, Вы писали:
Z>Пишу fluent интерфейс для конфигурации.
Z>Проблема в выводе типов метода Action2, хотя типы в Action, Action3 и SomeCfgAction2 выводятся прекрасно. Z>
Z> cfg.Action2(i => 1.0, ""); // The type arguments for method cannot be inferred from the usage
Z>
Z>Как написать метод Action2 чтобы он работал для Cfg и CfgExt и возвращал соответственно их же?
А как ВООБЩЕ только по лямбде i => 1.0 можно вывести тип T при приведении к Func<T, T2> arg, не задумывались?
Можно сделать с клиентской стороны так:
cfg.Action2((int i) => 1.0, "");
..то есть частично указать типы-параметры.
Других вариантов нет, в C# не настолько мощный вывод типов чтобы по неиспользованному имени в лямбде угадать какого оно типа
В других вариантах у Вас T выводится по другим аргументам, по Cfg<T>, например.
Здравствуйте, Ziaw, Вы писали:
Z>Здравствуйте, Ziaw, Вы писали:
Z>>Как написать метод Action2 чтобы он работал для Cfg и CfgExt и возвращал соответственно их же?
Z>забыл указать, C# 3.0
Изменения вывода типов в C# 4.0 влияют только на случаи приведения method group к типам делегатов, с лямбдами и анонимными методами ничего не изменилось.
Ваш сценарий вывода невозможен, так как вывод типов generic-методов в C# не умеет использовать constraint'ы для вывода типов других параметров:
public static TCfg Action4<TCfg, T>(this TCfg cfg)
where TCfg : Cfg<T>
{
return cfg;
}
cfg.Action4(); // The type arguments for method cannot be inferred from the usage
T может быть выведен только по другому аргументу, никак иначе.
p.s. Constraint'ы даже в сигнатуру то не входят, не используются в overload resolution.
Здравствуйте, Пельмешко, Вы писали:
П>Других вариантов нет, в C# не настолько мощный вывод типов чтобы по неиспользованному имени в лямбде угадать какого оно типа П>В других вариантах у Вас T выводится по другим аргументам, по Cfg<T>, например.
Жаль, хотя вполне ожидаем вывод из TCfg: Cfg<T>, первый аргумент нам точно известен.
Есть ли воркэраунд? Очень хочется fluent интерфес для потомков Cfg. Является ли написание идентичных Action2 для каждого потомка единственными выходом?
Здравствуйте, Ziaw, Вы писали:
Z>Здравствуйте, Пельмешко, Вы писали:
П>>Других вариантов нет, в C# не настолько мощный вывод типов чтобы по неиспользованному имени в лямбде угадать какого оно типа П>>В других вариантах у Вас T выводится по другим аргументам, по Cfg<T>, например.
Z>Жаль, хотя вполне ожидаем вывод из TCfg: Cfg<T>, первый аргумент нам точно известен.
Кстати, F# выводит:
type Cfg<'T>() =
member self.SomeCfgAction (arg : unit -> 'T, s : string) = ()
member self.SomeCfgAction2 (arg : 'T -> 'U, s : string) = ()
type CfgExt<'T>() =
inherit Cfg<'T>()
member self.SomeExtAction (arg : 'T) = ()
let action (cfg : #Cfg<'T>) (arg : unit -> 'T) s = cfg
let action2 (cfg : #Cfg<'T>) (arg : 'T -> 'U) s = cfg
let action3 (cfg : Cfg<'T>) (arg : 'T -> 'U) s = cfg
let cfg = Cfg()
action cfg (fun () -> 1) "" |> ignore
action2 cfg (fun i -> 1.0) "" |> ignore
action3 cfg (fun i -> 1.0) "" |> ignore
cfg.SomeCfgAction2((fun i -> 1.0), "")
Но зато не получилось сделать такой extension, чтобы первый параметр был generic-типа (TCfg), возможно вообще нельзя...