You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将C#游戏中的LINQ查询逻辑转换为数据驱动规则模式?

Data-Driven LINQ Queries Using Rule-Based Objects

Hey there! It sounds like you're already crushing it with the command pattern for data-driven actions—extending that approach to your LINQ queries is a smart move. Let's break down how to model those query operations as reusable, data-driven rules that you can tweak without recompiling.

Core Idea: Model Each LINQ Operation as a Rule

Just like your Command interface, we'll define a common interface for all query rules. Each rule represents one step in your LINQ chain (a Select, Where, or custom transformation), and we'll chain them together dynamically using the rules list.

Step 1: Define the Rule Interface

First, create an interface that every rule will implement. Since LINQ operations transform sequences of data, our rule's method will take an IEnumerable<float> and return a new transformed sequence:

public interface IQueryRule
{
    IEnumerable<float> Apply(IEnumerable<float> input);
}

Step 2: Implement Specific Rules

Now, turn each part of your original LINQ query into a concrete rule class. Each rule will encapsulate one operation, with configurable parameters so you can reuse them:

// Handles x => x + value
public class AddRule : IQueryRule
{
    private readonly float _valueToAdd;

    public AddRule(float valueToAdd)
    {
        _valueToAdd = valueToAdd;
    }

    public IEnumerable<float> Apply(IEnumerable<float> input)
    {
        return input.Select(x => x + _valueToAdd);
    }
}

// Handles Where(x => x < threshold)
public class LessThanFilterRule : IQueryRule
{
    private readonly float _threshold;

    public LessThanFilterRule(float threshold)
    {
        _threshold = threshold;
    }

    public IEnumerable<float> Apply(IEnumerable<float> input)
    {
        return input.Where(x => x < _threshold);
    }
}

// Handles x => x * multiplier
public class MultiplyRule : IQueryRule
{
    private readonly float _multiplier;

    public MultiplyRule(float multiplier)
    {
        _multiplier = multiplier;
    }

    public IEnumerable<float> Apply(IEnumerable<float> input)
    {
        return input.Select(x => x * _multiplier);
    }
}

// Handles x > max ? max : x
public class ClampUpperRule : IQueryRule
{
    private readonly float _maxValue;

    public ClampUpperRule(float maxValue)
    {
        _maxValue = maxValue;
    }

    public IEnumerable<float> Apply(IEnumerable<float> input)
    {
        return input.Select(x => x > _maxValue ? _maxValue : x);
    }
}

Step 3: Assemble Your Rules & Run the Query

Now, you can build your rules list to match the original LINQ query. For your example, the rules would look like this:

private float[] data;
public List<IQueryRule> rules;

// Initialize rules to match your original ExampleQuery
public void InitializeRules()
{
    rules = new List<IQueryRule>
    {
        new AddRule(2),
        new LessThanFilterRule(50),
        new MultiplyRule(3),
        new MultiplyRule(10),
        new ClampUpperRule(999)
    };
}

For the Query method, you don't need a manual foreach—use LINQ's Aggregate method to chain the rules together automatically. It takes your initial data sequence and applies each rule in order, just like the original LINQ chain:

public IEnumerable<float> Query()
{
    // Start with the data, then apply each rule in sequence
    return rules.Aggregate(data.AsEnumerable(), (currentSequence, rule) => rule.Apply(currentSequence));
}

Bonus: Make Rules Configurable/Serializable

If you want to load rules from external files (like JSON or XML) without recompiling, you can:

  • Add [Serializable] attributes to your rule classes
  • Use a factory pattern to instantiate rules from configuration data. For example, a JSON config might look like:
    [
      {"Type": "AddRule", "Parameters": {"ValueToAdd": 2}},
      {"Type": "LessThanFilterRule", "Parameters": {"Threshold": 50}},
      {"Type": "MultiplyRule", "Parameters": {"Multiplier": 3}},
      {"Type": "MultiplyRule", "Parameters": {"Multiplier": 10}},
      {"Type": "ClampUpperRule", "Parameters": {"MaxValue": 999}}
    ]
    
  • Use reflection or a dependency injection container to create rule instances from this config.

Key Benefits

  • No recompiles for new rules: Just add a new IQueryRule implementation and update your rules list (or config file)
  • Reusable rules: You can mix and match rules across different queries
  • Clear separation of concerns: Logic lives in rule classes, not monolithic query methods

内容的提问来源于stack exchange,提问作者Kevin Tanudjaja

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 14:17:31