【问题标题】:Is it possible to create a generic Func<T><T>是否可以创建通用 Func<T><T>
【发布时间】:2014-11-20 01:23:04
【问题描述】:

是否可以创建一个泛型Func&lt;T&gt;&lt;T&gt;,就像在接受泛型参数并需要返回该泛型参数类型的 Func 中一样?

换句话说,我可以这样做吗?

Func<T> createNull = () => default(T);

请注意,我没有来自包含类或方法的任何上下文,所以我想做:

var user = createNull<User>();

这里有一些关于我正在尝试做的事情的更多信息。(请注意语法是关闭的,因为我不知道如何去做,也不知道它是否可能):

Func<TQuery, TResult><TQuery, TResult> query = q => 
    (TResult) handlers[Tuple.Create(typeof(TQuery), typeof(TResult))](q);

其中 handlers 声明如下:

var handlers = new Dictionary<Tuple<Type, Type>, Func<TQuery, TResult><TQuery, TResult>();
// examples
handlers.Add(Tuple.Create(typeof(ById), typeof(User)), 
             idQuery => new User());
handlers.Add(Tuple.Create(typeof(ByName), typeof(Customer)), 
             otherQuery => new Customer());

那么我想像这样使用query

User result = query<User, IdQuery>(new ById{Id = 1});
Customer result1 = query<Customer, ByName>(new ByName());

【问题讨论】:

  • 只是一些建议。与其一遍又一遍地写出Dictionary&lt;Tuple&lt;Type, Type&gt;, Func&lt;TQuery, TResult&gt;&gt; 之类的东西,不如在文件顶部使用using HandlerCache = Dictionary&lt;Tuple&lt;Type, Type&gt;, Func&lt;TQuery, TResult&gt; 为它起别名,并且在整个文件中,您可以将其简单地称为HandlerCache(尽管在其他所有方面它都是丑陋的复合体类型)。不像 F# 那样流畅,但仍然很有帮助
  • 标题和开头句中的语法Func&lt;T&gt;&lt;T&gt; 没有意义。您的意思是 Func&lt;T1, T2&gt;Func&lt;TQuery, TResult&gt;(正如您稍后在问题中展示的那样)?

标签: c# generics lambda


【解决方案1】:

不,但你可以把它放在静态类中,几乎可以满足你的需求:

static class CreateNull<T>
{
   public static Func<T> Default = () => default(T);
}

var createNull = CreateNull<User>.Default;

【讨论】:

  • public static Func&lt;T&gt; Default&lt;T&gt;() { return () =&gt; default(T) } 然后泛型可以在方法上而不是在类上。你会调用Func&lt;User&gt; builder = CreateNull.Default&lt;User&gt;()
  • 谢谢,那是我试图避免的,我希望在一个班级中有多个不同类型的Func,但我已经认为这可能是不可能的。
【解决方案2】:

没有。泛型只能应用于方法、委托和类。

泛型是一种编译器功能,允许您编写一个方法,编译器将为所需的每组类型生成一个方法。所以如果你写:

public T DoSomething<T>(T input)

然后使用它:

int result1 = DoSomething(1);
double result2 = DoSomething(2.0);
MyType result3 = DoSomething(new MyType());

对于上面的每一行,JIT 都会生成一个新的方法重载。

Lambda 是类型化的,因​​此它们会生成相关委托的特定重载:

// Given generic Func<TInput, TResult>
Func<int, string> foo = (s) => Integer.parseInt(s);

【讨论】:

  • “泛型是一种编译器功能,允许您编写一个方法,编译器将为所需的每组类型生成一个方法。” 这不是真的。 .Net 不是 c++,IL 原生支持泛型。 You can prove this easily with ILSpy
  • @GeorgeMauer 感谢您的纠正!我猜错了。 JIT 按照这个答案来做:stackoverflow.com/a/5342424/545680
  • 有趣的是,如果您阅读引用,他实际上并没有说这就是 JIT 所做的。它只是创建副本作为优化,它不是实现的关键部分。请注意,他说所有引用类型(我们关心的 95%)都使用相同的 IL 代码,只有本机类型有自己的副本。
  • 是的。这就是为什么 .NET 不会像 Java 那样在原语上使用泛型而遭受装箱/拆箱惩罚。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-14
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 2016-10-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多