1+
2+ @page " /MappingPolymorphism"
3+
4+ <PageTitle >Mapping Polymorphism</PageTitle >
5+
6+ <h1 >Polymorphic Mapping</h1 >
7+
8+ <p >
9+ Polymorphic mapping enables you to map interface or base class types to their runtime implementations automatically.
10+ </p >
11+
12+ <h2 >Overview</h2 >
13+
14+ <p >
15+ When you map an interface or base class reference, the mapper examines the actual runtime type and routes it to the correct mapping.
16+ This is particularly useful when working with inheritance hierarchies or polymorphic collections.
17+ </p >
18+
19+ <h2 >Example Configuration:</h2 >
20+
21+ <CodeBlock Language =" CodeLanguage.CSharp" EnableLineNumbers =" false" Code =@MapperCode />
22+
23+ <h2 >Core Concepts</h2 >
24+
25+ <h3 >Type Dispatch</h3 >
26+
27+ <p >
28+ The mapper automatically detects the actual runtime type of your source object and dispatches it to the appropriate handler:
29+ </p >
30+
31+ <ul >
32+ <li >A <code >Dog</code > instance referenced as <code >IAnimal</code > is automatically mapped to <code >DogDto</code ></li >
33+ <li >A <code >Cat</code > instance referenced as <code >IAnimal</code > is automatically mapped to <code >CatDto</code ></li >
34+ <li >The dispatch happens transparently at runtime through pattern matching</li >
35+ </ul >
36+
37+ <h2 >Runtime Behavior</h2 >
38+
39+ <h3 >Successful Dispatch</h3 >
40+
41+ <p >
42+ When mapping an interface or base class reference:
43+ </p >
44+
45+ <ol >
46+ <li >The mapper checks the actual runtime type of the source object</li >
47+ <li >Finds the corresponding mapping in its registry</li >
48+ <li >Calls the appropriate <code >Map()</code > method</li >
49+ <li >Returns the correctly typed result</li >
50+ </ol >
51+
52+ <CodeBlock Language =" CodeLanguage.CSharp" EnableLineNumbers =" false" Code =@DispatchExample />
53+
54+ <h3 >Inheritance Chain Handling</h3 >
55+
56+ <p >
57+ When mapping a derived type through a base class reference:
58+ </p >
59+
60+ <ol >
61+ <li >The mapper first checks for an exact type match</li >
62+ <li >If found, it uses a specialized mapper (via <code >[UseMap< ;> ; ]</code >)</li >
63+ <li >The specialized mapper handles all derived-type-specific properties</li >
64+ </ol >
65+
66+ <CodeBlock Language =" CodeLanguage.CSharp" EnableLineNumbers =" false" Code =@InheritanceExample />
67+
68+ <h3 >Unhandled Types</h3 >
69+
70+ <p >
71+ If the mapper encounters a type without a registered mapping, it throws an <code >UnhandledPolymorphicTypeException</code >:
72+ </p >
73+
74+ <CodeBlock Language =" CodeLanguage.CSharp" EnableLineNumbers =" false" Code =@UnhandledTypeExample />
75+
76+ <p >
77+ <strong >Mitigation:</strong > Register all types that might be encountered:
78+ </p >
79+
80+ <CodeBlock Language =" CodeLanguage.CSharp" EnableLineNumbers =" false" Code =@MitigationExample />
81+
82+ <h2 >Best Practices</h2 >
83+
84+ <ul >
85+ <li ><strong >Register all possible types</strong > that might be encountered during mapping</li >
86+ <li ><strong >Use <code >[UseMap< ;> ; ]</code ></strong > for inheritance hierarchies with specialized behavior</li >
87+ <li ><strong >Keep interfaces aligned</strong > between source and destination types</li >
88+ <li ><strong >Test polymorphic paths</strong > to ensure all derived types are covered</li >
89+ <li ><strong >Handle exceptions gracefully</strong > if unhandled types are possible</li >
90+ </ul >
91+
92+ @code {
93+
94+ public const string MapperCode =
95+ """
96+ public interface IAnimal { public string Name { get; set; } }
97+ public interface IAnimalDto { public string Name { get; set; } }
98+
99+ public class Dog : IAnimal { public string Name { get; set; } }
100+ public class DogDto : IAnimalDto { public string Name { get; set; } }
101+
102+ public class Cat : IAnimal { public string Name { get; set; } }
103+ public class CatDto : IAnimalDto { public string Name { get; set; } }
104+
105+ public class Bird : IAnimal { public string Name { get; set; } }
106+ public class BirdDto : IAnimalDto { public string Name { get; set; } }
107+
108+ public class Wolf : Dog { public Color FurColor { get; set; } }
109+ public class WolfDto : DogDto { public Color FurColor { get; set; } }
110+
111+ [GenerateMapper]
112+ [Map<IAnimal, IAnimalDto>]
113+ [Map<Dog, DogDto>]
114+ [Map<Cat, CatDto>]
115+ [UseMap<WolfMapper, Wolf, WolfDto>]
116+ public partial class AnimalMapper;
117+
118+ [GenerateMapper(options: /* Adv. mapping configuration */)]
119+ [Map<Wolf, WolfDto>]
120+ public partial class WolfMapper
121+ {
122+ // Adv. mapping configuration
123+ }
124+ """ ;
125+
126+ public const string DispatchExample =
127+ """
128+ IAnimal source = new Dog { Name = "Piper" };
129+ IAnimalDto result = AnimalMapper.Map(source); // Returns DogDto with Name = "Piper"
130+ """ ;
131+
132+ public const string InheritanceExample =
133+ """
134+ IAnimal source = new Wolf { Name = "Ghost", FurColor = Color.GhostWhite };
135+ IAnimalDto result = AnimalMapper.Map(source); // Uses WolfMapper.Map(source)
136+
137+ // Result is WolfDto with both Name and FurColor populated
138+ var wolf = result as WolfDto;
139+ Console.WriteLine(wolf.Name); // "Ghost"
140+ Console.WriteLine(wolf.FurColor); // Color.GhostWhite
141+ """ ;
142+
143+ public const string UnhandledTypeExample =
144+ """
145+ IAnimal source = new Bird { Name = "Iago" };
146+ AnimalMapper.Map(source); // Throws UnhandledPolymorphicTypeException!
147+
148+ // Message: "Could not map type `Bird` to `IAnimalDto` - no matching destination type found."
149+ """ ;
150+
151+ public const string MitigationExample =
152+ """
153+ [GenerateMapper]
154+ [Map<IAnimal, IAnimalDto>]
155+ [Map<Dog, DogDto>]
156+ [Map<Cat, CatDto>]
157+ [Map<Bird, BirdDto>] // Register the Bird type
158+ [UseMap<WolfMapper, Wolf, WolfDto>]
159+ public partial class AnimalMapper;
160+ """ ;
161+
162+ }
0 commit comments