如何通过属性保留引用?AutoMapper处理Revit循环引用异常求助
PreserveReferences() and Fixing Your Circular Reference Stack Overflow Let's break down why you're still hitting a StackOverflowException even after using PreserveReferences(), and how to fix it by customizing equality checks for your mappings.
How PreserveReferences() Works by Default
AutoMapper's PreserveReferences() relies on reference equality (checking if two objects are the exact same instance in memory) to detect and break circular references during mapping. This works smoothly for most scenarios where source and destination objects align by reference.
But here's the key issue in your case: when mapping from Revit API's Element/Parameter to your custom Models.Element/Models.Parameter, AutoMapper is creating entirely new instances of your destination models. The default reference equality check can't track that a mapped Models.Parameter refers to the same Models.Element it already processed—since those are new objects, not the same reference. This leads to infinite recursive mapping and the stack overflow.
Customizing Equality Checks for Preserved References
Good news: AutoMapper lets you override the equality logic for preserved references with the .EqualityComparison() method. Since your Models.Element already uses Id for equality checks (via overridden Equals() and GetHashCode()), we can hook that logic into AutoMapper's reference tracking.
Updated Mapping Configuration
Modify your profile to add custom equality comparisons to both mappings, using the Id property to identify duplicate entities:
profile.CreateMap<Element, Models.Element>() .ForMember(element => element.Id, expression => expression.MapFrom(element => element.Id.IntegerValue)) .IncludeAllDerived() .PreserveReferences() .EqualityComparison((srcRevitElement, destCustomElement) => srcRevitElement.Id.IntegerValue == destCustomElement.Id); profile.CreateMap<Parameter, Models.Parameter>() .ForMember(parameter => parameter.Id, expression => expression.MapFrom(parameter => parameter.Id.IntegerValue)) .IncludeAllDerived() .PreserveReferences() .EqualityComparison((srcRevitParam, destCustomParam) => srcRevitParam.Id.IntegerValue == destCustomParam.Id);
Why This Fixes the Stack Overflow
- AutoMapper now tracks mapped destination objects using their
Idinstead of memory reference. - When it encounters a
Parameterthat references anElementit's already mapped, it reuses the existingModels.Elementinstance instead of creating a new one. This breaks the circular mapping chain that caused the infinite recursion.
Quick Additional Tip
For consistency, consider adding Equals() and GetHashCode() overrides to your Models.Parameter class as well, mirroring what you did for Models.Element. This ensures equality checks work reliably across all your mapped models.
内容的提问来源于stack exchange,提问作者Romain DA ROCHA

