如何传递函数不知道T的作用域

本文关键字:不知道 作用域 传递函数 | 更新日期: 2023-09-27 17:53:06

这可能不可能,但我希望它是!

我有一个方法,它的作用域是泛型类型,并且实例化了一个List<Func<GenericType>>。然后我有另一种方法,它接收List<Func<T>>。通过这种方法,我无法了解T

示例代码

public void PassFuncs<Item>()
{
  List<Func<Item>> funcs = new List<Func<Item>>();
  RecieveFuncs(funcs);
}
public void RecieveFuncs(List<Func<object>> funcs)
{
  //Do some stuff with funcs
}

我希望它会像使用object代替T一样容易,这将是很容易的。当然,T不是object,它是Type,因此我不能交换它们。有什么建议吗,还是这是不可能的?

如何传递函数<T>不知道T的作用域

你可以让你的方法泛型:

public void RecieveFuncs<T>(List<Func<T>> funcs)
{
  //Do some stuff with funcs
}
要调用它,您可以显式声明T
public void PassFuncs<Item>()
{
  List<Func<Item>> funcs = new List<Func<Item>>();
  RecieveFuncs<Item>(funcs);
}

或者让类型推断魔术完成它的工作并保持调用的原样:

public void PassFuncs<Item>()
{
  List<Func<Item>> funcs = new List<Func<Item>>();
  RecieveFuncs(funcs);  // C# automatically infers T = Item
}

如果由于某种原因不能使RecieveFuncs通用,您可以使用:

public void PassFuncs<TItem>()
    where TItem:class
{
  List<Func<TItem>> funcs = new List<Func<TItem>>();
  RecieveFuncs(funcs);
}
public void RecieveFuncs(IEnumerable<Func<object>> funcs)
{
  //Do some stuff with funcs
}

这需要对TItem的引用类型进行泛型约束,并且在接收端需要像IEnumerable<T>这样的协变接口而不是List<T>。如果你真的想收到一个List<Func<object>>,你可以用List<Func<object>>(funcs)创建一个新的列表。

如果您知道Item是引用类型,则可以使用每个函数的方差(但不是列表的方差):

public void PassFuncs<Item>() where Item : class
{
    List<Func<Item>> funcs = new List<Func<Item>>();
    var tmp = funcs.ConvertAll(func => (Func<object>)func);
    RecieveFuncs(tmp);
}

创建一个新的列表,但使用原来的函数。如果不可能,则需要添加一个中间函数:

public void PassFuncs<Item>()
{
    List<Func<Item>> funcs = new List<Func<Item>>();
    var tmp = funcs.ConvertAll<Func<object>>(func => () => func());
    RecieveFuncs(tmp);
}

您可以将Func<Item>"强制转换"为Func<object>,如下所示

public delegate object Func();
public void PassFuncs<Item>()
{
  List<Func<Item>> funcs = new List<Func<Item>>();
  RecieveFuncs(funcs.Select<Func<Item>, Func<object>>(f => () => (object)f())
                    .ToList());
}
public void RecieveFuncs(List<Func<object>> funcs)
{
  //Do some stuff with funcs
}

这对引用类型和值类型都有效,尽管它将为值类型装箱。如果您只使用引用类型,请使用@CodesInChaos答案。