LinkData#
A dependency between two tasks: which end of the source task drives which end of the target task, and the working time between them. Links go in ProjectData.Links. Build one with an object initializer; Id, Source and Target are required.
Declaration#
namespace Plen;
public sealed class LinkData : IDeepCloneable<LinkData>
LinkData has no constructor that sets the required properties, so new LinkData() without Id, Source and Target doesn't compile.
Properties#
| Property | Type | Default | Description |
|---|---|---|---|
Id |
Id |
required | Link id, unique among the project's links. |
Source |
Id |
required | Id of the predecessor task. |
Target |
Id |
required | Id of the successor task. |
LinkType |
LinkType |
LinkType.Fs |
Which end of Source drives which end of Target. |
Lag |
double |
0.0 |
Working time between the two ends, in LagUnit. Negative values are allowed. |
LagUnit |
TimeUnit? |
null |
Unit of Lag. null uses Config.DurationUnit. |
Id#
public required Id Id { get; set; }
The key that results use to refer to this link, for example in Note.DroppedLink, in a cycle's Links and in the critical path in Analytics. A string, int or double converts to Id implicitly.
Source, Target#
public required Id Source { get; set; }
public required Id Target { get; set; }
Ids of the two tasks the link connects. An id that names no task, or names an unscheduled task, doesn't fail validation. The link is dropped and reported as a Note.DroppedLink with the reason. See Links that get dropped for every case.
LinkType#
public LinkType LinkType { get; set; } = LinkType.Fs;
Fs (finish-to-start), Ss, Ff or Sf. See LinkType below.
Lag#
public double Lag { get; set; }
Working time added between the source end and the target end, in LagUnit. A negative value lets the target overlap the source. Must be a finite number. Lag is an absolute amount; a percentage of the predecessor's duration isn't supported.
LagUnit#
public TimeUnit? LagUnit { get; set; }
Unit for this link's Lag. null uses SchedulingConfig.DurationUnit.
Without a per-link LagUnit, lag is read in Config.DurationUnit.
Methods#
DeepClone#
public LinkData DeepClone()
Returns a copy with the same property values.
ToString#
public override string ToString()
Returns a readable rendering of every property, for logging.
LinkData doesn't override Equals; two instances compare by reference.
LinkType#
The dependency type of a link: which end of the source task drives which end of the target task.
namespace Plen;
public enum LinkType { Fs, Ss, Ff, Sf }
| Value | Description |
|---|---|
Fs |
Finish-to-start: the target starts after the source finishes. The default. |
Ss |
Start-to-start: the target starts after the source starts. |
Ff |
Finish-to-finish: the target finishes after the source finishes. |
Sf |
Start-to-finish: the target finishes after the source starts. |
Lag is added in every case. LinkAdd and LinkUpdate use the same enum. It has no parse or spelling helpers; JSON spellings are handled by the Plen.Wire package.
Errors#
The snapshot is validated when it's passed to Engine.Schedule or Project.Solve(data, …). A link makes the call throw InputException with Kind = InputErrorKind.Validation when:
- its
Idrepeats the id of an earlier link:Path = "links[i].id" - its
LagisNaNor infinite:Path = "links[i].lag"
Validation.Repair repairs a repeated id instead of throwing: the later link replaces the earlier one at the earlier position, and a Note.Repaired records it.
Links added or edited after the first solve go through LinkAdd and LinkUpdate.
Example#
Task 2 starts when task 1 finishes, and task 3 starts four hours after task 2 starts, while the project counts durations in days:
using Plen;
var start = Moment.FromYmdHm(2026, 4, 6, 8, 0)
?? throw new InvalidOperationException("invalid date");
var data = new ProjectData
{
Tasks =
[
new TaskData(1) { StartDate = start, Duration = 2.0 },
new TaskData(2) { StartDate = start, Duration = 3.0 },
new TaskData(3) { StartDate = start, Duration = 1.0 },
],
Links =
[
new LinkData { Id = "a", Source = 1, Target = 2 },
new LinkData
{
Id = "b",
Source = 2,
Target = 3,
LinkType = LinkType.Ss,
Lag = 4.0,
LagUnit = TimeUnit.Hour,
},
],
};
var result = Engine.Schedule(data, new SolveOptions());
foreach (var update in result.Updates)
{
Console.WriteLine(update);
}
Related#
ProjectData- the snapshot that holds linksLinkAdd- adds a link to a live projectLinkUpdate- edits a link in a live projectNote- reports dropped links- Links, constraints and summaries - link types, lag and dropped links