Currently working on a simple library that will take any object and fill it with fake data. It’ll be optionally configurable on a per object property basis and all that jazz. So far, so good!

So we’re in the middle of testing Snowflake as a data warehouse solution and in addition to testing out it’s performance and general experience, I wanted to make sure that I was going to be able to communicate with it from a .net core application. Right off the bat, a …
I responded to this question on reddit. I just wanted to archive this here —————————————– It is a puzzle that will never be fully solved, and a discipline that you will never master because its “mastery” in this field is purely subjective. I think it’s more about competency and flexibility …
I think that the topic of short-circuiting is an under-appreciated one. In short, short-circuiting is simply ending an evaluation the instant it becomes false:
1 2 3 |
if(2 < 1 && 1 == 1) { /* stuff */ } if(2 > 1 || 1 == 1) { /* stuff */ } |
In this example, the second condition doesn’t get evaluated in either case. In the first example, the compiler sees that both conditions have to be …
This is a follow up to my 2 video tutorial “Interfaces in C#”. There were some comments left on the YouTube thread suggesting that some folks are understanding how interfaces work, but still don’t see the point in using them. As always, I say that exposure is the best answer. …
Lambdas? That’s a frat right? Why are they in C#? No no… it’s not a frat! Lambdas are simply a syntax that we use to define anonymous methods. What’s an anonymous method? It’s a method that has no declaration. What’s a method declaration? Jeez man… Method Anatomy
1 2 3 4 |
public void DoStuff(int input) { Console.WriteLine("The number is {0}", input); } |
That is …
What is the Liskov Substition Principle (LSP)? Well, honestly, it’s a lot of things and I’m not going to try and explain them all in this article because I’m not even sure I understand it all lol. However, the one part of it I get is this: If T is …
Currently working on a simple library that will take any object and fill it with fake data. It’ll be optionally configurable on a per object property basis and all that jazz. So far, so good!
In these two vids, I take a beginner’s look at interfaces. Not just what they are, but why we use them…
In this article, I’m going to quickly go over a modified visitor pattern that I use for custom mapping when I’m not off abusing AutoMapper. Ā I’m not going to explain the visitor pattern here (maybe I will in a different blog, but today ain’t the day), but rather going over a slight bastardization of the pattern.
So let’s get one thing straight here before we start — patterns are solutions, not some sort of coder dogma. My point is, that the GoF patterns are time tested and true, but sometimes you just gotta… dance. Typically, when I see someone try to explain the visitor pattern, it’s either a total disaster of an explanation, I start to bleed from my eyes and ears, or … it’s a reporting example. In short, the reporting example basically sends in a visitor and that visitor traverses an object graph and collects a bunch of data. At the end, the visitor will have been updated with the final result of it’s trip into the bowels of it’s host object. Boring.
On of the other downsides to the textbook pattern is that any time you updated the visitor to handle a different object, you need to update the interface… and if you update the interface, then you gotta update every implementation of that interface. Boooooooo! This doesn’t aim to solve any of that; I’m just complaining. But, this thing outputs an object instead of simply collecting, and it doesn’t have that pesky interface problem. Alright, let’s get to it!
So for a while at my job, some of the leads were highly against AutoMapper for whatever reason, so we opted into doing all mapping by hand. Unfortunately, everything grew so fast that no standards were set in place and we ended up with, I shit you not, like 4 different mapping patterns, almost none of which were re-usable. To try and make an attempt at cleaning things up, I implemented this doozy.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
// this is the resuable base class public interface IMapper { T Map(object input); } public abstract class Mapper : IMapper { private Dictionary<Type, Func<object, T>> _mappers; public Dictionary<Type, Func<object, T>> Mappers { get { if(_mappers != null) return _mappers; _mappers = new Dictionary<Type, Func<object, T>>(); RegisterMappers(); return _mappers; } } public abstract void RegisterMappers(); public virtual T Map(object input) { // throws if not registered return Mappers[input.GetType()](input); } public void Register(Type input, Func<object, T> action) { Mappers.Add(input, action); } } |
So this base class takes care of most of the magic. All you have to do is implement it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
// these are sample implementations of the visitor public class Output1Mapper : Mapper // the mapper generic parameter is the type you want to output { public override void RegisterMappers() { // register by specifying your input type, and the function // that will run for that type Register(typeof(Input1), input => Map(input as Input1)); Register(typeof(Input2), input => Map(input as Input2)); } // the method that will run for Input1 public Output1 Map(Input1 input) { // in a real world example, we would use our input instance to instantiate // and hydrate an instance of our Output1 class. For this simple example, // we are just setting a single property via its constructor return new Output1(input.Input1Name); } // the method that will run for Input2 public Output1 Map(Input2 input) { return new Output1(input.Input2Name); } } |
So here’s what’s happening:
RegisterMappers
, we tell the class what types of objects we’re prepared to map. In this example, we’re saying that we’re going to support mappingĀ instances of Input1
and Input2
to an instance of Output1
Input1
, we’re going to call the method that takes Input1
. The compiler will know which one to use based on that cast (e.g. input as Input1)How do we use it?
1 2 3 4 5 6 7 8 9 10 |
// by adding this to your system namespace, all objects will be able to be // remapped using an instance of a mapper public static class Extensions { public static T Map(this object obj, IMapper mapper) { return mapper.Map(obj); } } |
What I’m doing here is adding an extension to the System.Object type that will allow me to apply a mapper to any instance of any object. Now to use the mapper, I simply need to call that extension with an instance of our mapper implementations. Here’s an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
void Main(string[] args) { var i1 = new Input1(); var i2 = new Input2(); IMapper mapper1 = new Output1Mapper(); IMapper mapper2 = new Output2Mapper(); // run the first mapper against our objects var mapped1 = i1.Map(mapper1); var mapped2 = i2.Map(mapper1); // run the second mapper against the same objects var mapped3 = i1.Map(mapper2); var mapped4 = i2.Map(mapper2); Console.WriteLine(mapped1.Message); // Mapped Input1 to Output1 Console.WriteLine(mapped2.Message); // Mapped Input2 to Output1 Console.WriteLine(mapped3.Message); // Mapped Input1 to Output2 Console.WriteLine(mapped4.Message); // Mapped Input2 to Output2 } |
Now here’s the neat thing. In true visitor fashion, you can reuse and chain these mappers together by using them inside of your mapper logic…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
public class Output1Mapper : Mapper // the mapper generic parameter is the type you want to output { public override void RegisterMappers() { // register by specifying your input type, and the function // that will run for that type Register(typeof(Input1), input => Map(input as Input1)); Register(typeof(Input2), input => Map(input as Input2)); } // the method that will run for Input1 public Output1 Map(Input1 input) { // in a real world example, we would use our input instance to instantiate // and hydrate an instance of our Output1 class. For this simple example, // we are just setting a single property via its constructor return new Output1 { Prop1 = input.InnerProp.Map(new Output2Mapper()), Prop2 = input.Name, Prop3 = input.InnerProp2.Map(new Output3Mapper()) }; } // the method that will run for Input2 public Output1 Map(Input2 input) { return new Output1(input.Input2Name); } } |
Now, as objects more and more complex and the composition gets deeper and deeper, this pattern really starts to save you time. You can reuse the mapper visitor, or invoke new ones at any point in the graph and polymorphism will take care of the rest.
This may seem kinda nuts but it’s really not. By creating mappers for all of your known objects, all you have to do in order add mapping logic for a new source object is to drop it in the existing mapper and register it. Or if you need to update the mapping logic, you only have to do it in one place. Over time, this becomes quite the time saver.
There are plenty of other solutions to this problem out there, but I think this one might help some of the anal retentive devs out there that want to make sure they have explicit control over everything that happens during a transformation like this. Hopefully, this will help someone out there!