通过匿名方法分配匿名类型的属性

15

我是C#函数式编程方面的新手,如果问题比较菜,敬请谅解。

以下是错误的代码:

var jobSummaries = from job in jobs
                   where ...
                   select new 
                   {
                        ID = job.ID,
                        Description = job.Description,
                        FileName = (job) => {
                                  // primitive logic not 
                                  // worth to become a named method
                                  try { return job.Files[0].LocalName); }
                                  catch { return null as string; }
                                 }
                   };

这段代码会产生如下的编译器错误:

无法将lambda表达式赋值给匿名类型属性

上述代码将委托设置为FileName属性,但这不是我的目的。我想让代码像这样工作,但不需要给方法命名:

var jobSummaries = from job in jobs
                   where ...
                   select new 
                   {
                        ID = job.ID,
                        Description = job.Description,
                        FileName = this.ExtractFileName(job)
                   };

...
private string ExtractFileName(Job job)
{
     try { return Path.GetFileName(job.Files[0].LocalName); }
     catch { return null as string; }
}
任何建议?
4个回答

17
直接调用匿名函数,可以这样做:
int result = new Func<int, int>( (int i) =>{ return i + 5; } ).Invoke(3);
// result = 8

但我同意,int result = (i => i + 5)(3);会更酷一些 =)


3
据我所知,你不能像那样内联lambda表达式,因为lambda表达式本身就是一个实例(类型为Expression<Func<T>>或类似类型)。
不过,你可以这样做(已更新计算fileName,因为现在由OP提供):
var jobSummaries = from job in jobs
                   where ...
                   let fileName = job.Files.Select(f => f.LocalName).FirstOrDefault()
                   select new 
                   {
                        ID = job.ID,
                        Description = job.Description,
                        FileName = fileName
                   };

请注意使用let关键字,它允许您直接在LINQ表达式中从job变量中提取文件名。

我刚刚尝试了一下。我无法使用“let”将lambda表达式设置为局部变量。我更新了示例代码。我有一个try/catch块,这使得直接计算变得困难。 - GarbageGuy
不,你不能将lambda表达式分配给fileName。只需编写代码:let fileName = Path.Combine(job.Folder, job.File)或者您需要的任何逻辑... - Mark Seemann
@GarbageGuy:我更新了我的回答,以反映您更新的问题,现在我知道您需要的算法。请注意,不需要使用try/catch。 - Mark Seemann
在您的特定示例中,try/catch结构不是必需的(请参见我的更新答案以获得更好的解决方案)。如果您的问题只是占位符,用于表示更复杂的内容,那么您是正确的,这并不能解决您的问题。您可以选择这里提供的其他解决方案之一,但我个人认为,如果您将复杂的代码封装在单独的方法或类中,代码会更清晰。您的情况可能有所不同。 - Mark Seemann
实际上,FirstOrDefault() 不适用于数组可能包含 0..N 个元素的情况,因此它也可能会抛出异常。但无论如何,根本问题是如何内联匿名方法,而不是如何避免它。无论如何,感谢您的贡献,我从中学到了东西! - GarbageGuy
显示剩余2条评论

2
编译器报错是因为您没有调用lambda函数,而是在定义它。如果编译器允许,您会有一个FileName属性是一个函数而不是一个值。
如果您可以将"primitive logic"写成一个表达式,那么您可以直接在赋值语句中写出来。

0

使用扩展程序来选择如何?这样你就可以在内部执行一些逻辑了。

var jobSummaries = jobs.Select(j =>
            {
                var someVar = j + "bla";
                return new
                    {
                        somelogic = someVar
                    };

            });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接