【问题标题】:LINQ conditional expression s not available in C#7.3LINQ 条件表达式在 C#7.3 中不可用
【发布时间】:2022-08-13 20:40:50
【问题描述】:

我正在使用带有实体框架和 LINQ 的 .Net 框架 4.7.3。

我正在尝试使用 LINQ 使用两个子类之一从数据库中填充一个新类,但是我遇到了我正在使用的语法错误,并且想知道如何才能绕过它。

错误是

CS8400:功能“目标类型条件表达式”在 C#7.3 中不可用

这是一个简化但完整的版本:

LINQ 查询(问题):

        return repo.Find() // Proprietary method returning IQueryable<T>
            .Select(x => new PostSnippet
            {
                Route = x.HasParams
                ? new DynamicDbRoute {
                    // Properties
                }
                : new StaticDbRoute {
                    // Properties
                }
            });

我想要填充的类:

public sealed class PostSnippet
{
    public string AltText { get; internal set; }
    public string AnchorText { get; internal set; }
    public string Image { get; internal set; }
    public int PostCount { get; internal set; }
    public string Title { get; internal set; }
    public IDbRoute Route { get; internal set; }
}

界面:

public interface IDbRoute
{
    string Url { get; }
}

类变体:

internal sealed class DynamicDbRoute : DbRoute, IDbRoute
{
    internal int NodeId { get; set; }
    internal ICollection<RouteParam> RouteParams { get; set; }
    internal string TopicName { get; set; }

    public override string GetRouteUrl()
    {
        // Implementation
    }
}

internal sealed class StaticDbRoute : DbRoute, IDbRoute
{
    public override string GetRouteUrl()
    {
        // Implementation
    }
}

基类:

internal abstract class DbRoute
{
    private string _url;

    public string Url => _url ?? (_url = GetRouteUrl());

    public string RouteName { get; set; }

    public abstract string GetRouteUrl();
}

我目前正试图让它工作,所以它可能不是完美的解决方案 - 随意加入 - 但主要我需要为查询找到一个可行的解决方案。任何帮助表示赞赏

  • 你不能在调用数据库之前输入?: 吗?
  • @tymtam - 不太清楚你的意思,但你当然可以这样做: ContentPhysicalFile = x.ContentBlock != null ? x.ContentBlock.PhysicalFile :默认
  • 不能移动到 C#9 或 10?
  • @McNets,不确定涉及什么,但听起来这超出了我的职权范围。

标签: c# linq


【解决方案1】:

问题是 C# 无法确定 C# 7.3 中三元表达式的返回类型。即,编译器不确定DynamicDbRouteStaticDbRoute 的公共基类型应该是DbRoute 还是IDbRoute

您可以通过将其中一个值转换为预期的公共基类型来帮助编译器,如下所示:

return repo.Find()
    .Select(x => new PostSnippet {
        Route = hasParams
        ? (IDbRoute)new DynamicDbRoute {      // Added: (IDbRoute)
            // Properties
        }
        : new StaticDbRoute {
            // Properties
        }
    });

现在,C# 7.3 编译器很高兴。

在 C# 9.0 中添加了Target-Typed Conditional Expressions。在 C# 9+ 中,编译器查看目标的类型(在本例中为 PostSnippet.Route 属性的类型,即 IDbRoute)以消除最佳公共基类型的歧义。

【讨论】:

  • 你完全正确,这已经解决了这个问题。
【解决方案2】:

为什么不考虑使用继承?查看此article 了解更多详情。
所以,而不是
public IDbRoute Route { get; internal set; }

将其更改为:
public DbRoute Route { get; internal set; }

比假设您的 EF 配置了继承,您可以使用 Include 操作,如下所示:

var entity = repo.Find().Include(e => e.Route).FirstOrDefault();

// now you can check which type you have
if (entity.Route is DynamicDbRoute dynamicDbRoute){
   // ... code
}

【讨论】:

    【解决方案3】:

    这可能是解决方案:

    bool hasParams = true; // Temp
    if(hasParams)
    {
        return repo.Find() // Proprietary method returning IQueryable<T>
          .Select(x => new PostSnippet
          {
            Route = new DynamicDbRoute {
                // Properties
                }
          });
    }
    else 
    {
        return repo.Find() // Proprietary method returning IQueryable<T>
          .Select(x => new PostSnippet
          {
            Route = new StaticDbRoute {
                // Properties
                }
          });
    }
    

    【讨论】:

    • 感谢您的解决方案。抱歉,但为了使问题更清楚,我实际上最终混淆了这件事。查询通常会返回多行,并且“HasParams”将在每行级别上,所以我不能在查询之外检查,只能在内部检查。我已经修改了这个例子。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-16
    • 1970-01-01
    • 2021-08-24
    • 1970-01-01
    相关资源
    最近更新 更多