Class PinnedCollectionSelection
How a PINNED collection on the composition root relates to the project's own adopted clones. A pinned
list is the author's chosen set, so adoption re-points it in place rather than replacing it: each
pinned member that has an adopted twin becomes that twin at the same position, every other member is
left exactly as it was, and nothing is appended — a project-owned definition the author never pinned
is reported to them, never added behind their back.
A list that already holds BOTH an origin and its twin loses the ORIGIN, the way label discovery drops
a shadowed one: rewriting it in place would put the twin in twice, and a collection carrying one Id
twice is what makes the game-settings service throw at boot. An entry that names nothing keeps its
slot — shrinking the author's list silently would hide the hole instead of reporting it.
The twin link is the Id rename rule (RenamedId(string)). Adoption
regenerates a clone's Guid, so there is no Guid lineage to follow.
Engine-agnostic and Unity-free — the caller decides what "Id" means for its own candidate type.
Inheritance
PinnedCollectionSelection
Assembly: Serenity.Global.Application.dll
Syntax
public static class PinnedCollectionSelection
Methods
HasNoLivingEntries<T>(IReadOnlyList<T>, Func<T, bool>)
True when nothing in pinned names anything, so the field asks for
label discovery — a list of empty slots pins no more than an empty list does.
Declaration
public static bool HasNoLivingEntries<T>(IReadOnlyList<T> pinned, Func<T, bool> isLiving) where T : class
Parameters
Returns
Type Parameters
LivingEntries<T>(IReadOnlyList<T>, Func<T, bool>)
The entries of pinned that still name something, in order. This is what "the
composition root pins anything" means everywhere it is asked — the runtime lookup and the editor
wiring both read it here, so a field whose every slot is empty is discovery mode to both of them.
Declaration
public static List<T> LivingEntries<T>(IReadOnlyList<T> pinned, Func<T, bool> isLiving) where T : class
Parameters
| Type |
Name |
Description |
| IReadOnlyList<T> |
pinned |
The list as the composition root carries it.
|
| Func<T, bool> |
isLiving |
Whether an entry still names something. A Unity reference needs the
engine's own null operator, which a plain reference check cannot stand in for.
|
Returns
Type Parameters
MissingEntryCount<T>(IReadOnlyList<T>, Func<T, string>)
How many entries of pinned name nothing — a reference the author left
empty, or one whose asset was deleted. They keep their slots, so the count is what gets reported.
Declaration
public static int MissingEntryCount<T>(IReadOnlyList<T> pinned, Func<T, string> idOf) where T : class
Parameters
Returns
Type Parameters
NotReachableFrom<T>(IReadOnlyList<T>, IReadOnlyList<T>, Func<T, string>)
The candidates no member of pinned names — neither pinned itself, nor the twin
of something pinned. These are the definitions a pinned installer will NOT load, which the author
has to be told about rather than have silently added.
Declaration
public static IReadOnlyList<T> NotReachableFrom<T>(IReadOnlyList<T> pinned, IReadOnlyList<T> candidates, Func<T, string> idOf) where T : class
Parameters
Returns
Type Parameters
WithAdoptedTwinsInPlace<T>(IReadOnlyList<T>, IReadOnlyList<T>, Func<T, string>)
pinned with every member that has exactly one adopted twin among
candidates replaced by that twin at its own position, every origin whose twin
the list already holds removed, and every remaining member — the ones naming nothing included —
left where it was.
Declaration
public static IReadOnlyList<T> WithAdoptedTwinsInPlace<T>(IReadOnlyList<T> pinned, IReadOnlyList<T> candidates, Func<T, string> idOf) where T : class
Parameters
| Type |
Name |
Description |
| IReadOnlyList<T> |
pinned |
The list as the composition root currently carries it.
|
| IReadOnlyList<T> |
candidates |
The project-owned assets an adopted twin could be among.
|
| Func<T, string> |
idOf |
The member's IFoundationSettings.Id (or equivalent).
|
Returns
Type Parameters