如何按字符串查找课程字段

时间:2019-06-23 12:21:40

标签: c# linq entity-framework-core

我有一个功能,可以根据字符串输入查找字段。我想检查该字段是否不为空,如果不为空,则返回该行。示例代码显示了硬编码的else-if语句(实际上更长一些)。我想知道是否有更简单的方法可以做到这一点。我的直觉说反射,但是我不知道该怎么做,或者不知道该怎么搜索。

public class Spell
{
    public string name { get; set; }
    public string description { get; set; }
    public string sor { get; set; }
    public string wiz { get; set; }
    public string cleric { get; set; }
}



public IEnumerable<Spell> GetSpellsForClass(string classname)
{
    if(classname =="sor")
        return _context.Spells.Where(x=> !string.IsNullOrEmpty(x.sor));
    else if (classname == "wiz")
        return _context.Spells.Where(x => !string.IsNullOrEmpty(x.wiz));
    else if(classname == "cleric")
        return _context.Spells.Where(x => !string.IsNullOrEmpty(x.cleric));
}

我希望输入'sor','wiz'或'cleric',并希望函数搜索相应的字段,检查其是否为空,然后返回整个对象。

4 个答案:

答案 0 :(得分:0)

您可以这样:

_context.Spells.Where(s => typeof(Spell).GetProperty(classname).GetValue(s) != null);

这样,您只需搜索类名(我建议使用propertyName代替变量名),而没有if else语句。

答案 1 :(得分:0)

将字典用于咒语类型是否更清洁?您可以拥有与拼写或某些不同标记相关的类的表。然后,您可以在类中拥有属性-假设您可以访问的CharacterClasses列表 ID。通过消除反射,这也可以提高您的性能。

答案 2 :(得分:0)

我认为您能做的最好是使用stmt->execute();将类名映射到访问相应成员的lambda方法。这将不如您的Dictionary / if方法(或更有效的是else / switch)方法有效。注意:如果您的case足够长,则编译器可能会生成一个案例哈希表以查找分支的位置。

提醒我们这是一个LINQ to EF查询,我已更新以构建适当的switch

给出:

Expression

还有一个Dictionary<string, Expression<Func<Spell, string>>> AccessSpellClass = new Dictionary<string, Expression<Func<Spell, string>>>() { { "sor", s => s.sor }, { "wiz", s => s.wiz }, { "cleric", s => s.cleric }, }; 用于替换ExpressionVisitor

Expression

您可以在您的方法中使用它:

public static class ExpressionExt {
    /// <summary>
    /// Replaces an Expression (reference Equals) with another Expression
    /// </summary>
    /// <param name="orig">The original Expression.</param>
    /// <param name="from">The from Expression.</param>
    /// <param name="to">The to Expression.</param>
    /// <returns>Expression with all occurrences of from replaced with to</returns>
    public static Expression Replace(this Expression orig, Expression from, Expression to) => new ReplaceVisitor(from, to).Visit(orig);
}

/// <summary>
/// ExpressionVisitor to replace an Expression (that is Equals) with another Expression.
/// </summary>
public class ReplaceVisitor : ExpressionVisitor {
    readonly Expression from;
    readonly Expression to;

    public ReplaceVisitor(Expression from, Expression to) {
        this.from = from;
        this.to = to;
    }

    public override Expression Visit(Expression node) => node == from ? to : base.Visit(node);
}

最好创建一个public IEnumerable<Spell> GetSpellsForClass(string classname) { if (AccessSpellClass.TryGetValue(classname, out var accessExpr)) { Expression<Func<string,bool>> testExpr = x => !String.IsNullOrEmpty(x); var newTestBody = testExpr.Body.Replace(testExpr.Parameters[0], accessExpr.Body); var newTestExpr = Expression.Lambda<Func<Spell,bool>>(newTestBody, accessExpr.Parameters[0]); return _context.Spells.Where(newTestExpr); } else return Enumerable.Empty<Spell>(); } ,然后在程序开始时在运行时构建Attribute

Dictionary

注意:如果不能使用自定义属性,则可以修改该方法以获取属性名称列表,并为这些属性构建字典条目。

答案 3 :(得分:-1)

这是使用扩展方法的基于反射的答案,我想这是您真正想要的。

public static bool TryIsPropertyNull(this object obj, string PropName, out bool isNull)
{
    isNull = false;
    var prop = obj.GetType().GetProperty(PropName);
    if (prop == null)
        return false;
    isNull = prop.GetValue(obj) == null;
    return true;
}

我这样做是为了“尝试”解决属性名称不存在的情况。 希望这可以为您提供正确方向的一些指示