尝试显式键入LINQ Select方法的结果
本文关键字:Select 方法 结果 LINQ | 更新日期: 2023-09-27 18:21:03
我仍在努力了解LINQ to Entities方法的一些细微差别。对于下面的代码块,我通常会为对象使用类型var
(下面的Comment 1),但由于foreach
循环没有嵌套在switch/case
块中(下面的Comment 2),我需要在switch/case
块之外定义emailList
的类型,并且我需要显式定义它(var
不再是选项)。那么emailList
的正确类型是什么呢?编译器不喜欢IQueryable<vwMaterialsDueAutoEmail>
。此外,当Emailstate为CancelNotice(下面的注释3)时,IQueryable<vwMaterialsDueAutoEmail>
的类型将不起作用。编译器似乎喜欢没有泛型类型<T>
的IQueryable
(下面的注释4),但当我在foreach中尝试使用emailList
时,我没有结果,所有检索email
属性(email.CaseName
、email.EmailAddress
…)的尝试都失败得很惨(下面的注意5)。我有80%的信心修复程序正确地键入了emailList
,并且在为其赋值时可能使用了某种类型的强制转换,但我不确定如何实现。
IQueryable emailList; // Comment 4: IQueryable with no <Type>
string subject;
string body = System.IO.File.ReadAllText(parameters.EmailBodyPath() +
@"'" + parameters.EmailBodyFile());
switch (parameters.EmailState)
{
case EmailState.MaterialsDue:
emailList = context.vwMaterialsDueAutoEmail.Select(d => new
// Comment 1: Normally I'd use var emailList.
{
CaseID = d.CaseID,
CaseName = d.CaseName,
EmailAddress = d.EmailAddress
});
break;
case EmailState.CancelNotice: //Comment 3: The other possible case.
emailList = context.vwRTCancelNoticeEmails.Select(d => new
// Omitted. Code similar to MaterialsDue.
default:
emailList = context.vwMaterialsDueAutoEmail;
// Will never be executed. Existence prevents "Use of unassigned variable" erorr
break;
}
foreach (var email in emailList)
// Comment 2: foreach is not in the switch/case block above
{
subject = "Materials Due: " + email.CaseName;
body = body.Replace("_CaseName_", email.CaseName);
//Comment 5: email problematic
SendEmail(email.EmailAddress, subject, "This is the body.");
}
执行new { Property = value... }
时,使用的是匿名类型。显然,匿名类型没有名字。由于该类型没有名称,因此无法显式定义它。(官方有一个名称,但这个名称是由编译器指定的…)
此外,由于在不同的位置使用匿名类型,因此会有很大的变化——所有这些类型都会不同,因此很难将它们分配给同一个emailList
,因为emailList
需要同时为三个类型。
解决方案可以是创建自己的KNOWN类型,用参数CaseID
、CaseName
等定义。在Select方法中使用此类型,然后emailList
可以定义为IQueryable<MyKnownType>
。
创建一个接口,表示可以通过电子邮件通知的类型
public interface IEmailNotifiable
{
EmailContent Content {get;}
}
然后将IQueryable emailList;
更改为IQueryable<IEmailNotifiable>;
然后创建一些实现该接口的其他类,在select语句中构造这些类。
emailList = context.vwMaterialsDueAutoEmail.Select(d => new
MaterialsDueEmailNotification(d.CaseID, d.CaseName, d.EmailAddress));
只要MaterialsDueEmailNotification
实现IEmailNotifiable
,就可以有效地转换,因为IQueryable<T>
是协变的。
然后:
foreach (var email in emailList)
{
SendEmail(email.Content);
}
现在,我不仅解决了类型问题,还将电子邮件的确切内容的结构移交给了适当的类,因此理论上,电子邮件的内容和结构可能会根据创建的类而发生很大变化。