[Canonical page](<https://docs.dhtmlx.com/planning-engine/net/api/core/evaluate/evaluate-result/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# EvaluateResult

Every candidate of one [`Project.Evaluate`](<https://docs.dhtmlx.com/planning-engine/net/api/project-evaluate.md>) or [`Project.EvaluateWith`](<https://docs.dhtmlx.com/planning-engine/net/api/project-evaluate.md#evaluatewith>) call, scored against one baseline. The call returns it; there's no other way to get one.

## Declaration

```csharp
namespace Plen;

public sealed class EvaluateResult : IDeepCloneable<EvaluateResult>, IEquatable<EvaluateResult>
{
    public required string BaselineId { get; set; }
    public required Metrics Baseline { get; set; }
    public List<CandidateResult> Candidates { get; set; } = [];

    public EvaluateResult DeepClone();
    public bool Equals(EvaluateResult? other);
}
```

## Properties

| Property | Type | Description |
|---|---|---|
| `BaselineId` | `string` | Token of the accepted baseline the candidates were scored against. |
| `Baseline` | [`Metrics`](<https://docs.dhtmlx.com/planning-engine/net/api/core/evaluate/metrics.md>) | Metrics of the reference state. Every delta in it is `0`. |
| `Candidates` | `List<`[`CandidateResult`](<https://docs.dhtmlx.com/planning-engine/net/api/core/evaluate/candidate-result.md>)`>` | One result per candidate, in input order. |

### BaselineId

```csharp
public required string BaselineId { get; set; }
```

The project's accepted baseline token at the time of the call. It's always set, and it stays the accepted state's token when [`EvaluateOptions.ClearFirst`](<https://docs.dhtmlx.com/planning-engine/net/api/core/evaluate/evaluate-options.md>) is `true`. Pass it as `BaselineId` in the [`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/scheduling-changes.md>) of the candidate you commit, so [`Project.Apply`](<https://docs.dhtmlx.com/planning-engine/net/api/project-apply.md>) rejects the commit if the project changed in between.

### Baseline

```csharp
public required Metrics Baseline { get; set; }
```

The reference every candidate is compared with: the accepted state, or its cleared copy when `ClearFirst` is `true`. Deltas are `0` by definition. `Baseline.Cost` is the baseline's own cost, so a candidate with a lower [`CandidateResult.Cost`](<https://docs.dhtmlx.com/planning-engine/net/api/core/evaluate/candidate-result.md>) scores better than leaving the plan as it is.

### Candidates

```csharp
public List<CandidateResult> Candidates { get; set; } = [];
```

One [`CandidateResult`](<https://docs.dhtmlx.com/planning-engine/net/api/core/evaluate/candidate-result.md>) per input candidate, in the order of the `candidates` argument, with sequential and parallel execution alike. A failed candidate stays in the list with its `Error` set and no metrics; a call-level error throws instead (see [`Project.Evaluate`](<https://docs.dhtmlx.com/planning-engine/net/api/project-evaluate.md#errors>)).

## Methods

### DeepClone

```csharp
public EvaluateResult DeepClone()
```

Returns a copy that shares no list or nested object with this one.

### Equals

```csharp
public bool Equals(EvaluateResult? other)
public override bool Equals(object? obj)
```

Value equality: `BaselineId` and `Baseline` are equal and `Candidates` match element by element. `GetHashCode` is consistent with it.

### ToString

```csharp
public override string ToString()
```

Returns a readable dump of all properties, for logging.

## Example

Score two staffing options for task `1`, then commit the one with the lowest cost:

```csharp
using Plen;

var monday = Moment.FromYmdHm(2026, 8, 10, 8, 0)
    ?? throw new InvalidOperationException("invalid date");

var data = new ProjectData
{
    Tasks = [new TaskData(1) { StartDate = monday, Duration = 2.0 }],
    Resources = [new ResourceData { Id = "dev1" }, new ResourceData { Id = "dev2" }],
};

var project = new Project();
project.Solve(data, new SolveOptions());

var candidates = new List<Candidate>();
foreach (var dev in new[] { "dev1", "dev2" })
{
    var changes = new SchedulingChanges();
    changes.Assignments.Add.Add(new AssignmentData { Task = 1, Resource = dev, Value = 1.0 });
    candidates.Add(new Candidate { Id = dev, Changes = changes });
}

var result = project.Evaluate(candidates, new EvaluateOptions());
Console.WriteLine($"baseline cost: {result.Baseline.Cost}");

CandidateResult? best = null;
foreach (var c in result.Candidates)
{
    if (c.Error is not null || c.Cost is null)
        continue;
    if (best is null || c.Cost < best.Cost)
        best = c;
}

if (best is not null)
{
    var chosen = candidates.First(c => c.Id.Equals(best.Id)).Changes;
    chosen.BaselineId = result.BaselineId;
    project.Apply(chosen);
    project.Solve(null, new SolveOptions());
}
```

## Related

- [`Project.Evaluate`](<https://docs.dhtmlx.com/planning-engine/net/api/project-evaluate.md>) - the call that returns it
- [`CandidateResult`](<https://docs.dhtmlx.com/planning-engine/net/api/core/evaluate/candidate-result.md>) - the score of one candidate
- [`Metrics`](<https://docs.dhtmlx.com/planning-engine/net/api/core/evaluate/metrics.md>) - the baseline and stage metrics
- [`EvaluateOptions`](<https://docs.dhtmlx.com/planning-engine/net/api/core/evaluate/evaluate-options.md>) - the options of the call
- [Evaluating alternatives](<https://docs.dhtmlx.com/planning-engine/net/resources-and-assignment/evaluating-alternatives.md#committing-the-winner>) - comparing candidates and committing the winner
