Home > Mobile >  LINQ conditional expression s not available in C#7.3
LINQ conditional expression s not available in C#7.3

Time:08-13

I'm using .Net framework 4.7.3, with Entity Framework and LINQ.

I'm trying to populate a new class from the database with one of two sub-classes using LINQ, but I'm running into an error with the syntax I'm using and wondered how I could possibly get around it.

The error is

CS8400: Feature 'target-typed conditional expression' is not available in C#7.3

Here's a simplified but complete version:

LINQ query (The problem):

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

Class I'm wanting to populate:

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; }
}

Interface:

public interface IDbRoute
{
    string Url { get; }
}

Class Variants:

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
    }
}

Base class:

internal abstract class DbRoute
{
    private string _url;

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

    public string RouteName { get; set; }

    public abstract string GetRouteUrl();
}

I'm currently trying to get this to work so it might not be the perfect solution - feel free to chip in - but primarily I need to get a working solution for the query. Any help appreciated

CodePudding user response:

The problem is that C# cannot determine the return type of the ternary expression in C# 7.3. I.e., the compiler is not sure whether the common base type of DynamicDbRoute and StaticDbRoute should be DbRoute or IDbRoute.

You can help the compiler by casting one of the values to the expected common base type like this:

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

Now, the C# 7.3 compiler is happy.

The Target-Typed Conditional Expressions have been added in C# 9.0. In C# 9 , the compiler looks at the type of the target (the type of the PostSnippet.Route property in this case, which is IDbRoute) to disambiguate the best common base type.

Note, you can use this new feature (and many more) in older Framework versions if you set <LangVersion>latest</LangVersion> in the project file. See: C# language versioning. You also will also need Microsoft Visual Studio 2019 . See: Minimum SDK version needed to support all language features

CodePudding user response:

why not consider using Inheritance? check out this article for more details.
so that instead of
public IDbRoute Route { get; internal set; }

change it to:
public DbRoute Route { get; internal set; }

than Assuming you have your EF configured with inheritance in mind you can use the Include action as follow:

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

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

CodePudding user response:

This could be the solution:

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
            }
      });
}
  • Related