Table of Contents

Class XFactory

Namespace
Hi.Common.XmlUtils
Assembly
HiGeom.dll

Factory for generating objects from XML elements using registered generator functions.

public class XFactory
Inheritance
XFactory
Inherited Members
Extension Methods

Remarks

Each XFactory instance owns its own Generators registry. A process-wide Default singleton serves the common case (single shared factory across the simulation pipeline); other instances can be created for test isolation or parallel pipelines that need disjoint registries.

Types that participate in XML round-trip expose a public static void Reg(XFactory factory = null) method that adds themselves (and chains Reg(factory) on dependents) to the given factory's Generators. Boot roots (e.g. LocalProjectService.Reg()) call the top-level Reg() once at startup with the default factory.

The static Gen<T> / GenByChild<T> / GenByFile<T> entry points always read from Default. Callers that need to deserialize from a custom factory's registry must look up the delegate directly, as the entry points do: factory.TypedGenerators[(xname, typeof(T))] first, then factory.Generators[xname].

The element's name, not T, picks the generator, and the generator decides the type of the object it builds — unless a generator is registered for the element name and the type asked for (TypedGenerators), which is taken before the one registered for the name alone, by every entry point (GenListSkippingUnloadable<T>(IEnumerable<XElement>, string, IProgress<IMessage>, bool, object[]) asks for its T). When that object is not a T, the static entry points that read one object (Gen, GenByChild and GenByFile) return null — the GenFileRefSource family a FileRefSource<T> whose data is null — and report an XFactory-Load--TypeMismatch error on their progress, naming the element, the type it is read as and T; GenListSkippingUnloadable<T>(IEnumerable<XElement>, string, IProgress<IMessage>, bool, object[]) skips such an element with a warning. An element name that is not registered throws KeyNotFoundException from the entry points that read one object.

Properties

Default

Process-wide default factory used by the static Gen<T> family. Reg-style methods register here when called with no explicit factory argument.

public static XFactory Default { get; }

Property Value

XFactory

Generators

XML-name → generator-function map for this factory instance. Populated by each type's Reg(this) call. Concurrent so that parallel Reg calls (e.g. independent test classes each booting the registration graph) can TryAdd without corrupting the map.

public ConcurrentDictionary<string, XFactory.XGeneratorDelegate> Generators { get; }

Property Value

ConcurrentDictionary<string, XFactory.XGeneratorDelegate>

TypedGenerators

(XML name, type asked for) → generator-function map for this factory instance. A generator registered for the element name and the type asked for is taken before the one registered for the name alone in Generators, and only for that type: the type asked for must equal the type registered (not a base class of it, not an interface it implements). A type's legacy reading registers here — the element whose name is read as another type today is still read as the type a caller of an earlier version asks for. Concurrent for the same reason as Generators.

public ConcurrentDictionary<(string XName, Type Type), XFactory.XGeneratorDelegate> TypedGenerators { get; }

Property Value

ConcurrentDictionary<(string XName, Type Type), XFactory.XGeneratorDelegate>

Methods

GenByChild<T>(XElement, string, IProgress<IMessage>, bool, object[])

Generates an object of type T from the first child element (discards relative file path).

public static T GenByChild<T>(XElement src, string baseDirectory, IProgress<IMessage> progress, bool enableRebase = true, object[] res = null) where T : class

Parameters

src XElement
baseDirectory string
progress IProgress<IMessage>
enableRebase bool
res object[]

Returns

T

Type Parameters

T

Remarks

Returns null and reports on progress in the cases Gen<T>(XElement, string, out string, IProgress<IMessage>, bool, object[]) lists.

GenByChild<T>(XElement, string, out string, IProgress<IMessage>, bool, object[])

Generates an object of type T from the first child element of the provided XML element.

public static T GenByChild<T>(XElement src, string baseDirectory, out string relFile, IProgress<IMessage> progress, bool enableRebase = true, object[] res = null) where T : class

Parameters

src XElement
baseDirectory string
relFile string
progress IProgress<IMessage>
enableRebase bool
res object[]

Returns

T

Type Parameters

T

Remarks

Returns null and reports on progress in the cases Gen<T>(XElement, string, out string, IProgress<IMessage>, bool, object[]) lists.

GenByFile<T>(string, string, IProgress<IMessage>, bool, object[])

Generates an object of type T from an XML file.

public static T GenByFile<T>(string baseDirectory, string relFile, IProgress<IMessage> progress, bool enableRebase = true, object[] res = null) where T : class

Parameters

baseDirectory string
relFile string
progress IProgress<IMessage>
enableRebase bool
res object[]

Returns

T

Type Parameters

T

Remarks

The file's root element picks the generator, so the root element, not T, decides the type of the object read (a generator registered for the root element's name and T itself, TypedGenerators, first). A file that cannot be read, or whose root element is read as a type that is not a T, yields null and an error on progress (XmlSource-Read–Failed or XFactory-Load–TypeMismatch); see Gen<T>(XElement, string, out string, IProgress<IMessage>, bool, object[]).

GenFileRefSourceByChild<T>(XElement, string, IProgress<IMessage>, bool, object[])

Generates a FileRefSource<T> from the first child element.

public static FileRefSource<T> GenFileRefSourceByChild<T>(XElement src, string baseDirectory, IProgress<IMessage> progress, bool enableRebase = true, object[] res = null) where T : class, IMakeXmlSource

Parameters

src XElement
baseDirectory string
progress IProgress<IMessage>
enableRebase bool
res object[]

Returns

FileRefSource<T>

Type Parameters

T

Remarks

GenFileRefSourceByFile<T>(string, string, IProgress<IMessage>, bool, object[])

Generates a FileRefSource<T> from an XML file.

public static FileRefSource<T> GenFileRefSourceByFile<T>(string baseDirectory, string relFile, IProgress<IMessage> progress, bool enableRebase = true, object[] res = null) where T : class, IMakeXmlSource

Parameters

baseDirectory string
relFile string
progress IProgress<IMessage>
enableRebase bool
res object[]

Returns

FileRefSource<T>

Type Parameters

T

Remarks

GenFileRefSource<T>(XElement, string, IProgress<IMessage>, bool, object[])

Generates a FileRefSource<T> from an XML element.

public static FileRefSource<T> GenFileRefSource<T>(XElement src, string baseDirectory, IProgress<IMessage> progress, bool enableRebase = true, object[] res = null) where T : class, IMakeXmlSource

Parameters

src XElement
baseDirectory string
progress IProgress<IMessage>
enableRebase bool
res object[]

Returns

FileRefSource<T>

Type Parameters

T

Remarks

GenListSkippingUnloadable<T>(IEnumerable<XElement>, string, IProgress<IMessage>, bool, object[])

Deserializes each element of elements into a T, skipping — instead of throwing on — any element whose XName is not registered (e.g. a renamed or removed component), whose generator throws, or whose generator builds an object that is not a T. Each skipped element is reported to progress as a Warning (XFactory-Load–SkippedUnloadable, naming the element, T and the reason). An element that yields no object — an <XmlSource> whose file cannot be read, reported as XmlSource-Read–Failed — is left out without a warning. A generator registered for the element name and T (TypedGenerators) is taken before the one registered for the name alone, as by Gen<T>. Use when a partially-loadable list (such as a saved pipeline whose schema has drifted while a feature is in development) is preferable to aborting the whole load.

public static List<T> GenListSkippingUnloadable<T>(IEnumerable<XElement> elements, string baseDirectory, IProgress<IMessage> progress, bool enableRebase = true, object[] res = null) where T : class

Parameters

elements IEnumerable<XElement>
baseDirectory string
progress IProgress<IMessage>
enableRebase bool
res object[]

Returns

List<T>

Type Parameters

T

Gen<T>(XElement, string, IProgress<IMessage>, bool, object[])

Generates an object of type T from an XML element (discards relative file path).

public static T Gen<T>(XElement src, string baseDirectory, IProgress<IMessage> progress, bool enableRebase = true, object[] res = null) where T : class

Parameters

src XElement
baseDirectory string
progress IProgress<IMessage>
enableRebase bool
res object[]

Returns

T

Type Parameters

T

Remarks

Returns null and reports on progress in the cases Gen<T>(XElement, string, out string, IProgress<IMessage>, bool, object[]) lists.

Gen<T>(XElement, string, out string, IProgress<IMessage>, bool, object[])

Generates an object of type T from an XML element using Default.

public static T Gen<T>(XElement src, string baseDirectory, out string relFile, IProgress<IMessage> progress, bool enableRebase = true, object[] res = null) where T : class

Parameters

src XElement
baseDirectory string
relFile string
progress IProgress<IMessage>
enableRebase bool
res object[]

Returns

T

Type Parameters

T

Remarks

An <XmlSource> wrapper whose file cannot be read yields null — never an exception — and an XmlSource-Read--Failed error on progress naming the resolved path; relFile still receives the reference so the holder can keep it (and write it back on save through MakeXmlSourceToFileRef(IMakeXmlSource, string, string, bool)).

The element's name — for an <XmlSource> wrapper, the name of the root element of the file it refers to — picks the generator, so it decides the type of the object read, not T; a generator registered for the element name and T itself (TypedGenerators) is taken before the one registered for the name alone. When that object is not a T, the result is null and an XFactory-Load--TypeMismatch error on progress names the element, the type it is read as and T; read such an element as that type, a base class of it or an interface it implements. A generator that builds nothing yields null without a report, and a null progress takes no report. An element name that is not registered throws KeyNotFoundException.