Overview of the POCO model

The FHIR POCO (Plain Old CLR Object) model in the Hl7.Fhir.Model namespace maps FHIR resources and data types to idiomatic .NET classes. The UML diagram below shows the principal classes and interfaces and the relationships described in this chapter.

Historically, the class hierarchy has evolved: in FHIR STU3 and R4 most datatypes inherited directly from Element. R5 introduced intermediate types such as Base, PrimitiveType, and DataType to better structure shared behavior. The .NET SDK adopts these concepts retroactively, so the SDK POCOs for STU3 and R4 also use these base classes. As a result, the class hierarchy shown here reflects the SDK’s unified view and applies to all supported FHIR versions, even when the original STU3 and R4 definitions did not explicitly include these intermediate types.

The diagram explicitly includes Code and Code<T>: Code<T> is a SDK-specific construct (not part of the FHIR specification) that represents enumerable codes. The diagram also shows PocoNode; although this class is not part of the FHIR specification, it is important for integrating POCOs with code that uses ITypedElement and ISourceNode.

classDiagram class Base { <<abstract>> bool HasOverflow CompareChildren(...) TryGetValue(...) SetValue(...) EnumerateElements() } class IAnnotated { Annotations(Type) } class IAnnotatable { <<interface>> AddAnnotation(object) RemoveAnnotations(Type) } IAnnotatable --|> IAnnotated Base ..|> IAnnotatable class Element{ <<abstract>> string ElementId } class PocoNode { PocoNode Parent string Name int Index IEnumerable~PocoNodeOrList~ Children() PocoNodeOrList Child(string name) } PocoNode ..|> ITypedElement PocoNode ..|> ISourceNode PocoNode *-- Base Element --|> Base BackboneElement --|> Element class BackboneElement { <<abstract>> List~Extension~ ModifierExtension } note for BackboneElement "Nested classes like Patient.Contact derive from BackboneElement" class DomainResource{ <<abstract>> Narrative Text List~Resource~ Contained } note for DomainResource "Most resources derive from DomainResource" Resource --|> Base DomainResource --|> Resource class DataType { <<abstract>> } PrimitiveType --|> DataType class PrimitiveType { <<abstract>> object JsonValue bool HasValidValue() bool TryConvertToSystemType(out Any) } note for PrimitiveType "All FHIR primitive types (e.g., FhirString, FhirBoolean) derive from PrimitiveType" Code --|> PrimitiveType class Code { string Value string Literal string System } CodeOfT --|> Code class CodeOfT { new T Value } note for DataType "Non-primitive datatypes derive from DataType" DataType --|> Element class Resource { <<abstract>> string ResourceType Uri ResourceBase } note for Resource "Bundle, Parameters, Binary derive directly from Resource"

Dynamic types in the model

The SDK also provides dynamic types for representing instances that do not have a compiled POCO in the SDK. The parsers create these runtime types when they encounter unknown resource types or data that have no corresponding .NET class.

classDiagram class IDynamicType{ <<interface>> string DynamicTypeName } DynamicResource --|> DomainResource DynamicResource ..|> IDynamicType DynamicPrimitive --|> PrimitiveType DynamicPrimitive ..|> IDynamicType DynamicDataType --|> DataType DynamicDataType ..|> IDynamicType DynamicInfraResource --|> Resource DynamicInfraResource ..|> IDynamicType

Modifier extensions in the model

The FHIR specification treats modifier extensions differently from regular extensions: modifier extensions convey additional information that changes the core meaning of the element they modify, and they therefore require careful handling. The SDK indicates which classes may carry modifier extensions by using the IModifierExtendable interface.

As shown in the diagram, most typical FHIR resources support both Extension and modifier extensions, but some infrastructure resources such as Bundle and Parameters (which derive directly from Resource) do not support extensions at all. Also, primitive types may have regular Extension instances but cannot have modifier extensions.

classDiagram class IModifierExtendable { <<interface>> List~Extension~ ModifierExtension } IModifierExtendable ..|> IExtendable BackboneElement ..|> IModifierExtendable BackboneType ..|> IModifierExtendable DomainResource ..|> IModifierExtendable DomainResource --|> Resource note for BackboneType "Non-primitive datatypes that can have modifier extensions derive from BackboneType" class BackboneType { <<abstract>> } class IExtendable { <<interface>> List~Extension~ Extension } BackboneType --|> DataType Element ..|> IExtendable Element --|> Base Resource --|> Base DataType --|> Element