Когда вы передаете Func<TResult>
в метод Run<TResult>(Func<TResult>)
, вам не нужно указывать общий код метода, потому что он может его вывести. Ваша лямбда делает этот вывод.
Однако ваша функция на самом деле не является Func<TResult>
, тогда как лямбда была.
Если вы выполняете Func<Int32> f = MyIntReturningMethod
, это работает. Теперь, если вы укажете Task.Run<Int32>(MyIntReturningMethod)
, вы ожидаете, что он тоже будет работать. Однако он не может решить, должно ли оно разрешить перегрузку Func<Task<TResult>>
или перегрузку Func<TResult>
, и это не имеет особого смысла, поскольку очевидно, что метод не возвращает задачу.
Если вы скомпилируете что-то вроде следующего:
void Main()
{
Thing(MyIntReturningMethod);
}
public void Thing<T>(Func<T> o)
{
o();
}
public Int32 MyIntReturningMethod()
{
return (5);
}
IL выглядит так:
IL_0001: ldarg.0
IL_0002: ldarg.0
IL_0003: ldftn UserQuery.MyIntReturningMethod
IL_0009: newobj System.Func<System.Int32>..ctor
IL_000E: call UserQuery.Thing
(Некоторые из дополнительных материалов из добавлений LINQ Pad ... как часть UserQuery)
IL выглядит одинаково, как если бы вы делали явное приведение. Таким образом, похоже, что компилятор действительно не знает, какой метод использовать. Поэтому он не знает, что делать для автоматического создания.
Вы можете просто использовать Task.Run<Int32>((Func<Int32>)MyIntReturningMethod)
, чтобы немного помочь. Хотя я согласен, что это похоже на компилятор, с которым можно справиться. Поскольку Func<Task<Int32>>
не совпадает с Func<Int32>
, поэтому не имеет смысла, что они путают компилятор.
clang
(libc ++) кажется несовместимым по этому вопросу, потому что стандарт гласит:
~unique_ptr();
blockquote>
Требуется: Выражение
get_deleter()(get())
должно быть правильно сформированным, иметь четко определенное поведение и не должно создавать исключений. [ Примечание: Использованиеdefault_delete
требует, чтобыT
был полным типом. - конечная нота ]Эффекты: если
get() == nullptr
нет эффектов. В противном случаеget_deleter()(get())
.Таким образом, деструктор должен быть эквивалентен
get_deleter()(get())
, из чего следует, чтоb->a
не может бытьnullptr
внутри деструктора изA
(который вызывается внутриget_deleter()
какdelete
инструкция).
С другой стороны, и
clang
(libc ++), иgcc
(libstdc ++) устанавливают указатель наnullptr
при уничтоженииstd::unique_ptr
, но вот деструкторgcc
:auto& __ptr = _M_t._M_ptr(); if (__ptr != nullptr) get_deleter()(__ptr); __ptr = pointer();
... и вот
clang
(вызовreset()
):pointer __tmp = __ptr_.first(); __ptr_.first() = pointer(); if (__tmp) __ptr_.second()(__tmp);
Как видите,
gcc
сначала удаляет, а затем присваиваетnullptr
] (pointer()
), в то время какclang
сначала присваиваетnullptr
(pointer()
), затем удаляет 1 sup>.
1 sup>
pointer
- это псевдоним, соответствующийDeleter::pointer
, если он существует, или простоT*
.