Class TypeHash
Produces a stable type hash for a Type based on its layout in memory and how that memory should be interpreted.
Namespace: Unity.Entities
Assembly: solution.dll
Syntax
public class TypeHash
Remarks
You can rename field members and this hash isn't affected. However, if a field's type changes, this hash changes, because the interpretation of the underlying memory will have contextually changed.
The purpose of the stable type hash is to provide a version linking serialized component data to its runtime representation.
As such, the type hash has a few requirements:
- R0: TypeHashes apply only to types that Unity.Entities serializes. The internals of a UnityEngine.Object reference contained in a component mustn't have an effect on the type hash. You can safely change the internals of the UnityEngine.Object reference because they're serialized outside of Unity.Entities.
- R1: Types with the same data layout but are different types should have different hashes.
- R2: If a type's data layout changes, so should the type hash. This includes:
- A nested field's data layout changes (for example, a new member added)
- FieldOffsets, explicit size, or pack alignment are changed
- Different types of the same width swap places (for example if a uint swaps with an int)
- Note: Unity can't detect if fields of the same type swap (for example, mInt1 swaps with mInt2) This is a semantic difference which you should increase your component [TypeVersion(1)] attribute. You shouldn't try to hash field names to handle this, because you can't control all field names. Also, field names have no effect serialization and doesn't affect hashes.
- R3: You should version the hash in case the semantics of a type change, but the data layout is unchanged
- R4: DOTS Runtime relies on hashes generated from the Editor (used in serialized data) and hashes generated
during compilation. These hashes must match. This rule exists because of the following:
- Tiny swapa out assemblies for 'tiny' versions, which means you should avoid any hashing using the AssemblyName
or handle it specially for the known swapped assemblies.
- This means you should avoid Type.AssemblyQualifiedName in hashes, but as well, closed-form
generic types include the assembly qualified name for GenericArguments in Type.FullName which
causes issues. For example,
typeof(ComponentWithGeneric.GenericField).FullName == Unity.Entities.ComponentWithGeneric.GenericField
1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]`
- This means you should avoid Type.AssemblyQualifiedName in hashes, but as well, closed-form
generic types include the assembly qualified name for GenericArguments in Type.FullName which
causes issues. For example,
- System.Reflection and Mono.Cecil provide different Type names (they use a different format). Generating hashes from System.Reflection to match hashes using Mono.Cecil must account for this difference.
- Tiny swapa out assemblies for 'tiny' versions, which means you should avoid any hashing using the AssemblyName
or handle it specially for the known swapped assemblies.
Methods
Name | Description |
---|---|
CalculateMemoryOrdering(Type, out bool, Dictionary<Type, ulong>) | Calculates a MemoryOrdering for the input type. |
CalculateStableTypeHash(Type, IEnumerable<CustomAttributeData>, Dictionary<Type, ulong>) | Calculates a stable type hash for the input type. |
CombineFNV1A64(ulong, ulong) | Combines a FNV1A64 hash with a value. |
FNV1A64(int) | Generates a FNV1A64 hash. |
FNV1A64(string) | Generates a FNV1A64 hash. |
FNV1A64<T>(T) | Generates a FNV1A64 hash. |