尝试显式键入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.CaseNameemail.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.");
   }

尝试显式键入LINQ Select方法的结果

执行new { Property = value... }时,使用的是匿名类型。显然,匿名类型没有名字。由于该类型没有名称,因此无法显式定义它。(官方有一个名称,但这个名称是由编译器指定的…)

此外,由于在不同的位置使用匿名类型,因此会有很大的变化——所有这些类型都会不同,因此很难将它们分配给同一个emailList,因为emailList需要同时为三个类型。

解决方案可以是创建自己的KNOWN类型,用参数CaseIDCaseName等定义。在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);
}

现在,我不仅解决了类型问题,还将电子邮件的确切内容的结构移交给了适当的类,因此理论上,电子邮件的内容和结构可能会根据创建的类而发生很大变化。