Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在运行时为OrderBy/Where选择属性(不使用字符串参数)?_C#_Linq_Linq To Entities_Expression Trees - Fatal编程技术网

C# 如何在运行时为OrderBy/Where选择属性(不使用字符串参数)?

C# 如何在运行时为OrderBy/Where选择属性(不使用字符串参数)?,c#,linq,linq-to-entities,expression-trees,C#,Linq,Linq To Entities,Expression Trees,更新示例以显示更一般的用法 我有一个允许用户提供本地化的实体: public class ResourceValue { public int ResourceValueId { get; set; } public string EnglishValue { get; set; } public string FrenchValue { get; set; } public string SpanishValue { get; set; } etc...

更新示例以显示更一般的用法

我有一个允许用户提供本地化的实体:

public class ResourceValue
{
    public int ResourceValueId { get; set; }
    public string EnglishValue { get; set; }
    public string FrenchValue { get; set; }
    public string SpanishValue { get; set; }
    etc...
}
用于许多其他实体,如:

public class SomeEntity
{
    public int Id { get; set; }
    public virtual ResourceValue Name { get; set; }
    public virtual ResourceValue ShortDescription { get; set; }
    public virtual ResourceValue LongDescription { get; set; }
    etc...
}
return context.SomeEntities.OrderBy(x => x.Name);
    private static IQueryable<SomeEntity> OrderByName(IQueryable<SomeEntity> source, string culture)
    {
        if (culture == "fr-CA")
        {
            return source.OrderBy(x => x.Name.FrenchValue);
        }

        return source.OrderBy(x => x.Name.EnglishValue);
    }
我想这样做:

public class SomeEntity
{
    public int Id { get; set; }
    public virtual ResourceValue Name { get; set; }
    public virtual ResourceValue ShortDescription { get; set; }
    public virtual ResourceValue LongDescription { get; set; }
    etc...
}
return context.SomeEntities.OrderBy(x => x.Name);
    private static IQueryable<SomeEntity> OrderByName(IQueryable<SomeEntity> source, string culture)
    {
        if (culture == "fr-CA")
        {
            return source.OrderBy(x => x.Name.FrenchValue);
        }

        return source.OrderBy(x => x.Name.EnglishValue);
    }
把这项工作当作我做过的:

return context.SomeEntities.OrderBy(x => x.Name.FrenchValue);
基于当前的UICulture为“fr CA”

根据马克·格雷威尔的回答,我一直在尝试一些事情:但没能得到我想要的

更新-这非常接近,但我更希望将其命名为“OrderBy”,以便最终编码人员可以使用它而无需特别考虑:

    public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector)
    {
        return ApplyLocalizedOrder(source, keySelector, "OrderBy");
    }

    public static IOrderedQueryable<TSource> ApplyLocalizedOrder<TSource, TKey>(IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, string methodName)
    {
        ParameterExpression arg = keySelector.Parameters[0];
        Expression expr = Expression.PropertyOrField(keySelector.Body, GetCurrentCulture());
        LambdaExpression lambda = Expression.Lambda<Func<TSource, string>>(expr, arg);

        return (IOrderedQueryable<TSource>)typeof(Queryable).GetMethods().Single(
                method => method.Name == methodName
                        && method.IsGenericMethodDefinition
                        && method.GetGenericArguments().Length == 2
                        && method.GetParameters().Length == 2)
                .MakeGenericMethod(typeof(TSource), expr.Type)
                .Invoke(null, new object[] { source, lambda });
    }
public static IOrderedQueryable OrderBy(此IQueryable源、表达式keySelector)
{
返回ApplyLocalizedOrder(源、键选择器、“OrderBy”);
}
公共静态IOrderedQueryable ApplyLocalizedOrder(IQueryable源、表达式键选择器、字符串方法名)
{
ParameterExpression arg=keySelector.Parameters[0];
Expression expr=Expression.PropertyOrField(keySelector.Body,GetCurrentCulture());
LambdaExpression lambda=Expression.lambda(expr,arg);
return(IOrderedQueryable)typeof(Queryable).GetMethods().Single(
method=>method.Name==methodName
&&方法.IsGenericMethodDefinition
&&方法。GetGenericArguments()。长度==2
&&方法。GetParameters().Length==2)
.MakeGenericMethod(typeof(TSource),expr.Type)
.Invoke(null,新对象[]{source,lambda});
}

虽然动态创建lambda表达式很酷,但只需创建一个将排序应用于查询顶部的方法,就可以以更简单的方式获得结果。方法如下所示:

public class SomeEntity
{
    public int Id { get; set; }
    public virtual ResourceValue Name { get; set; }
    public virtual ResourceValue ShortDescription { get; set; }
    public virtual ResourceValue LongDescription { get; set; }
    etc...
}
return context.SomeEntities.OrderBy(x => x.Name);
    private static IQueryable<SomeEntity> OrderByName(IQueryable<SomeEntity> source, string culture)
    {
        if (culture == "fr-CA")
        {
            return source.OrderBy(x => x.Name.FrenchValue);
        }

        return source.OrderBy(x => x.Name.EnglishValue);
    }
以下是整个示例:

public class MyCtx1 : DbContext
{
    public DbSet<SomeEntity> SomeEntities { get; set; }
    public DbSet<ResourceValue> ResourceValues { get; set; }
}

public class SomeEntity
{
    public int Id { get; set; }
    public virtual ResourceValue Name { get; set; }
}

public class ResourceValue
{
    public int ResourceValueId { get; set; }
    public string EnglishValue { get; set; }
    public string FrenchValue { get; set; }
}

class Program
{

    private static IQueryable<SomeEntity> OrderByName(IQueryable<SomeEntity> source, string culture)
    {
        if (culture == "fr-CA")
        {
            return source.OrderBy(x => x.Name.FrenchValue);
        }

        return source.OrderBy(x => x.Name.EnglishValue);
    }

    static void Main(string[] args)
    {
        using (var context = new MyCtx1())
        {
            if (!context.SomeEntities.Any())
            {
                context.SomeEntities.Add(
                    new SomeEntity() 
                    { 
                        Name = new ResourceValue()
                        {
                            EnglishValue = "abc - en",
                            FrenchValue = "xyz - fr"
                        }
                    });

                context.SomeEntities.Add(
                    new SomeEntity() 
                    { 
                        Name = new ResourceValue()
                        {
                            EnglishValue = "xyz - en",
                            FrenchValue = "abc - fr"
                        }
                    });

                context.SaveChanges();
            }

            Console.WriteLine("Ordered by english name");
            DisplayResults(OrderByName(context.SomeEntities, "en-US"));

            Console.WriteLine("Ordered by french name");
            DisplayResults(OrderByName(context.SomeEntities, "fr-CA"));
        }
    }

    private static void DisplayResults(IQueryable<SomeEntity> q)
    {
        foreach (var e in q)
        {
            Console.WriteLine(e.Id);
        }                
    }

但是,甚至比在
get
for name中更好的是,返回当前区域性或某个区域性或代码调用的任何内容,当您的类可以这样做时,没有理由在Linq查询中这样做。当它在类中完成时,无论如何都会更好,因为无论在哪里调用代码,它都会返回正确的区域性。

在这种特定情况下,这会起作用,但我希望在许多实体的几十个字段上使用ResourceValue。例如,某些实体可能还具有可本地化的ShortDescription、LongDescription等。