SlideShare a Scribd company logo
Observations on the
Implementation of Design
Patterns in C# and .NET
Dmitri Nesteruk
@dnesteruk
Why design patterns?
Design patterns are no longer as
fashionable
Still relevant, translated to most
OOP languages
We assume everyone knows
them
Made a video course on them
(book might happen)
Design pattern and architecture-
related observations
Local Inversion of Control
Normal control: x.foo(y)
Inverted control: y.foo(x)
Implemented using e.g. extension methods
Names.Add(name);
“Names should add to itself the name”
name.AddTo(Names);
“Take name and add to Names”
public static T AddTo<T>(
this T self,
ICollection<T> c)
{
c.Add(self);
return self;
}
name.AddTo(Names);
name.AddTo(Names)
.AddTo(OtherNames)
.SomeOtherStuff();
op == "AND" || op == "OR" || op == "XOR"
Operation is AND or OR or XOR
new[]{"AND","OR","XOR"}.Contains(op)
This list of operations contains our operation (ugly)
op.IsOneOf("AND","OR","XOR")
Operation is one of the following
public static bool IsOneOf<T>(
this T self,
params T[] items)
{
return items.Contains(self);
}
Composite
Exposing collections and scalar objects in a uniform
way
Different scales:
Properties
Entire objects
Property Composite
I have names {FirstName, MiddleName, LastName}
Sometimes, I want an individual name
person.FirstName
Sometimes, I want to print the full name
string.Join(" ", person.Names)
How do I get person.Names?
public class Person
{
string FirstName, … { get; }
public IEnumerable<string> Names
{
yield return FirstName;
…
}
}
Array-Backed Properties
Suppose I want to add Title before the names…
How should I expose it?
Why not store names contiguously?
Never accidentally fail to yield a name from Names
Easier serialization (never miss a property)
Many aggregate get-only properties (e.g., full name
without title)
public class Person
{
private string names[4];
public string Title
{
get { return names[0]; }
set { names[0] = value; }
}
public string FullNameNoTitle
=> names.Skip(1).Join(' ');
}
Composite at Class Scale
Neural network model
A single neuron can be
connected to another
neuron
A bunch of neurons form a
layer
We want all forms of
entities to be connectable
class Neuron
{
public List<Neuron> In, Out;
}
class Neuron
{
public List<Neuron> In, Out;
public void ConnectTo(Neuron other)
{
Out.Add(other);
other.In.Add(this);
}
}
public class NeuronLayer :
Collection<Neuron> {}
var neuron1 = new Neuron();
var neuron2 = new Neuron();
var layer1 = new NeuronLayer();
var layer2 = new NeuronLayer();
neuron1.ConnectTo(neuron2);
neuron1.ConnectTo(layer1);
layer2.ConnectTo(neuron1);
layer1.ConnectTo(layer2);
Hot to make a single ConnectTo()?
Cannot make a base class: NeuronLayer already has
one
Use a common interface
NeuronLayer is an IEnumerable<Neuron>
So why not make Neuron IEnumerable<Neuron>
too?
class Neuron : IEnumerable<Neuron>
{
public List<Neuron> In, Out;
public void ConnectTo(Neuron other)
{
Out.Add(other);
other.In.Add(this);
}
}
public class Neuron : IEnumerable<Neuron>
{
public List<Neuron> In, Out;
public IEnumerator<Neuron> GetEnumerator()
{
yield return this;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public static void ConnectTo(
this IEnumerable<Neuron> self,
IEnumerable<Neuron> other)
{
if (ReferenceEquals(self, other)) return;
foreach (var from in self)
foreach (var to in other)
{
from.Out.Add(to);
to.In.Add(from);
}
}
var neuron1 = new Neuron();
var neuron2 = new Neuron();
var layer1 = new NeuronLayer();
var layer2 = new NeuronLayer();
neuron1.ConnectTo(neuron2);
neuron1.ConnectTo(layer1);
layer2.ConnectTo(neuron1);
layer1.ConnectTo(layer2);
Dynamic in Design Patterns
Runtime-constructed Null Object
Dynamic Proxy
Dynamic Visitor
Null Object
A no-op object that can be injected when required
Typically conforms to an interface
We might not want to explicitly construct such an
object (e.g., for testing)
Dynamic to the rescue!
public interface ILog
{
void Info(string msg);
void Warn(string msg);
}
class ConsoleLog : ILog
{
public void Info(string msg)
{
WriteLine(msg);
}
⋮
}
public class BankAccount
{
private ILog log;
private int balance;
public BankAccount(ILog log) { this.log = log; }
public void Deposit(int amount)
{
balance += amount;
log.Info(
$"Deposited ${amount}, balance is now {balance}");
}
}
Problem
We have a hard dependency on ILog
We cannot supply null – too many NREs
We cannot rewrite existing code to use ?.
everywhere
Log may be passed on to other components
How to make a log that does nothing?
sealed class NullLog : ILog
{
public void Info(string msg) {}
public void Warn(string msg) {}
}
public class Null<T> :
DynamicObject where T:class
{
⋮
}
override bool TryInvokeMember(
InvokeMemberBinder binder,
object[] args, out object result)
{
result = Activator.CreateInstance(
binder.ReturnType);
return true;
}
public static T Instance
{
get
{
// ImpromptuInterface
return new Null<T>().ActLike<T>();
}
}
var log = Null<ILog>.Instance;
var ba = new BankAccount(log);
Dynamic Visitor
Dispatch = how many pieces of info do I need to
know what to call?
Static dispatch = all information must be known at
compile time 
Then what’s the point of polymorphism?
interface IStuff { }
class Foo : IStuff { }
class Bar : IStuff { }
static void f(Foo foo) { }
static void f(Bar bar) { }
IStuff i = new Foo();
f(i); // cannot resolve
// call needs to be on i
public abstract class Expression
{
public abstract void Accept(IExpressionVisitor visitor);
}
public interface IExpressionVisitor
{
void Visit(DoubleExpression de);
void Visit(AdditionExpression ae);
}
public class DoubleExpression : Expression
{
override void Accept(IExpressionVisitor visitor)
{
visitor.Visit(this);
}
} // f⋆⋆⋆ this, too much work!
interface IStuff { }
class Foo : IStuff { }
class Bar : IStuff { }
static void f(Foo foo) { }
static void f(Bar bar) { }
IStuff i = new Foo();
f((dynamic)i); // woo-hoo!
// dynamic dispatch!
Dynamic Proxy
Null Object: remove logging from entity
Dynamic Proxy: add logging to entity (at runtime!)
Implementations of Null<T> and Log<T> are
almost identical…
public class Log<T> : DynamicObject
where T : class, new()
{
private readonly T subject;
private Dictionary<string, int> methodCallCount =
new Dictionary<string, int>();
protected Log(T subject)
{
this.subject = subject;
}
⋮
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
try
{
// logging
WriteLine($"Invoking {subject.GetType().Name}.{binder.Name} ([{string.Join(",", args)}])");
// more logging
if (methodCallCount.ContainsKey(binder.Name)) methodCallCount[binder.Name]++;
else methodCallCount.Add(binder.Name, 1);
result = subject.GetType().GetMethod(binder.Name).Invoke(subject, args);
return true;
}
catch
{
result = null;
return false;
}
}
public static I As<I>() where I : class
{
// ensure I is an interface
return new Log<T>(new T())
.ActLike<I>();
}
public string Info
{
get
{
var sb = new StringBuilder();
foreach (var kv in methodCallCount)
sb.AppendLine($"{kv.Key} called {kv.Value} time(s)");
return sb.ToString();
}
}
// will not be proxied automatically
public override string ToString()
{
return $"{Info}{subject}";
}
var ba = Log<BankAccount>.As<IBankAccount>();
ba.Deposit(100);
ba.Withdraw(50);
WriteLine(ba); // ToString()
// DynamicObject overrides :(
That’s it!
Questions? Answers? Hate mail? @dnesteruk
Design Patterns in .NET online course at http://bit.ly/2p3aZww
ImpromptuInterface: https://github.com/ekonbenefits/impromptu-interface

More Related Content

What's hot (20)

PDF
Declarative Thinking, Declarative Practice
Kevlin Henney
 
PDF
Python Functions (PyAtl Beginners Night)
Rick Copeland
 
PPT
Oop objects_classes
sidra tauseef
 
PPTX
TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB
tdc-globalcode
 
PPTX
Expression trees in c#, Алексей Голубь (Svitla Systems)
Alina Vilk
 
PDF
Free Monads Getting Started
Kent Ohashi
 
PDF
Functions in python
Ilian Iliev
 
PDF
Что нам готовит грядущий C#7?
Andrey Akinshin
 
PDF
Easy Going Groovy 2nd season on DevLOVE
Uehara Junji
 
PDF
Functions
Marieswaran Ramasamy
 
ODP
Python quickstart for programmers: Python Kung Fu
climatewarrior
 
PPT
Paradigmas de Linguagens de Programacao - Aula #4
Ismar Silveira
 
PDF
Compiler Construction | Lecture 14 | Interpreters
Eelco Visser
 
PDF
Let's go Developer 2011 sendai Let's go Java Developer (Programming Language ...
Uehara Junji
 
PDF
Declarative Type System Specification with Statix
Eelco Visser
 
KEY
Code as data as code.
Mike Fogus
 
ODP
Naïveté vs. Experience
Mike Fogus
 
PDF
The Macronomicon
Mike Fogus
 
PPTX
Introduction to Python and TensorFlow
Bayu Aldi Yansyah
 
PDF
Go Java, Go!
Andres Almiray
 
Declarative Thinking, Declarative Practice
Kevlin Henney
 
Python Functions (PyAtl Beginners Night)
Rick Copeland
 
Oop objects_classes
sidra tauseef
 
TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB
tdc-globalcode
 
Expression trees in c#, Алексей Голубь (Svitla Systems)
Alina Vilk
 
Free Monads Getting Started
Kent Ohashi
 
Functions in python
Ilian Iliev
 
Что нам готовит грядущий C#7?
Andrey Akinshin
 
Easy Going Groovy 2nd season on DevLOVE
Uehara Junji
 
Python quickstart for programmers: Python Kung Fu
climatewarrior
 
Paradigmas de Linguagens de Programacao - Aula #4
Ismar Silveira
 
Compiler Construction | Lecture 14 | Interpreters
Eelco Visser
 
Let's go Developer 2011 sendai Let's go Java Developer (Programming Language ...
Uehara Junji
 
Declarative Type System Specification with Statix
Eelco Visser
 
Code as data as code.
Mike Fogus
 
Naïveté vs. Experience
Mike Fogus
 
The Macronomicon
Mike Fogus
 
Introduction to Python and TensorFlow
Bayu Aldi Yansyah
 
Go Java, Go!
Andres Almiray
 

Similar to Design Pattern Observations (20)

PDF
Javascript fundamentals for php developers
Chris Ramakers
 
PDF
Introduction to Functional Programming
Hoàng Lâm Huỳnh
 
PDF
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
James Titcumb
 
PPT
Java Serialization
jeslie
 
PDF
エンタープライズ・クラウドと 並列・分散・非同期処理
maruyama097
 
PDF
Functional Programming You Already Know
Kevlin Henney
 
PPTX
L04 Software Design 2
Ólafur Andri Ragnarsson
 
PPT
Go OO! - Real-life Design Patterns in PHP 5
Stephan Schmidt
 
PPTX
Introducing PHP Latest Updates
Iftekhar Eather
 
PDF
C# for Java Developers
Jussi Pohjolainen
 
PDF
Kotlin for android developers whats new
Serghii Chaban
 
PDF
What can be done with Java, but should better be done with Erlang (@pavlobaron)
Pavlo Baron
 
PDF
Object-oriented Basics
Jamie (Taka) Wang
 
PDF
Design patterns illustrated 010PHP
Herman Peeren
 
PPT
Implementation of interface9 cm604.30
myrajendra
 
PPT
شرح مقرر البرمجة 2 لغة جافا - الوحدة السابعة
جامعة القدس المفتوحة
 
PDF
Hipster oriented programming (Mobilization Lodz 2015)
Jens Ravens
 
PPT
Java Generics
jeslie
 
PDF
Functional Programming You Already Know - Kevlin Henney - Codemotion Rome 2015
Codemotion
 
PPT
Mixing functional and object oriented approaches to programming in C#
Mark Needham
 
Javascript fundamentals for php developers
Chris Ramakers
 
Introduction to Functional Programming
Hoàng Lâm Huỳnh
 
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
James Titcumb
 
Java Serialization
jeslie
 
エンタープライズ・クラウドと 並列・分散・非同期処理
maruyama097
 
Functional Programming You Already Know
Kevlin Henney
 
L04 Software Design 2
Ólafur Andri Ragnarsson
 
Go OO! - Real-life Design Patterns in PHP 5
Stephan Schmidt
 
Introducing PHP Latest Updates
Iftekhar Eather
 
C# for Java Developers
Jussi Pohjolainen
 
Kotlin for android developers whats new
Serghii Chaban
 
What can be done with Java, but should better be done with Erlang (@pavlobaron)
Pavlo Baron
 
Object-oriented Basics
Jamie (Taka) Wang
 
Design patterns illustrated 010PHP
Herman Peeren
 
Implementation of interface9 cm604.30
myrajendra
 
شرح مقرر البرمجة 2 لغة جافا - الوحدة السابعة
جامعة القدس المفتوحة
 
Hipster oriented programming (Mobilization Lodz 2015)
Jens Ravens
 
Java Generics
jeslie
 
Functional Programming You Already Know - Kevlin Henney - Codemotion Rome 2015
Codemotion
 
Mixing functional and object oriented approaches to programming in C#
Mark Needham
 
Ad

More from Dmitri Nesteruk (20)

PDF
Good Ideas in Programming Languages
Dmitri Nesteruk
 
PDF
CallSharp: Automatic Input/Output Matching in .NET
Dmitri Nesteruk
 
PDF
Design Patterns in Modern C++
Dmitri Nesteruk
 
PPTX
C# Tricks
Dmitri Nesteruk
 
PPTX
Introduction to Programming Bots
Dmitri Nesteruk
 
PDF
Converting Managed Languages to C++
Dmitri Nesteruk
 
PDF
Monte Carlo C++
Dmitri Nesteruk
 
PDF
Tpl DataFlow
Dmitri Nesteruk
 
PDF
YouTrack: Not Just an Issue Tracker
Dmitri Nesteruk
 
PPTX
Проект X2C
Dmitri Nesteruk
 
PPTX
Domain Transformations
Dmitri Nesteruk
 
PDF
Victor CG Erofeev - Metro UI
Dmitri Nesteruk
 
PDF
Developer Efficiency
Dmitri Nesteruk
 
PPTX
Distributed Development
Dmitri Nesteruk
 
PDF
Dynamics CRM Data Integration
Dmitri Nesteruk
 
PDF
Web mining
Dmitri Nesteruk
 
PDF
Data mapping tutorial
Dmitri Nesteruk
 
PDF
Reactive Extensions
Dmitri Nesteruk
 
PDF
Design Patterns in .Net
Dmitri Nesteruk
 
PDF
Metaprogramming
Dmitri Nesteruk
 
Good Ideas in Programming Languages
Dmitri Nesteruk
 
CallSharp: Automatic Input/Output Matching in .NET
Dmitri Nesteruk
 
Design Patterns in Modern C++
Dmitri Nesteruk
 
C# Tricks
Dmitri Nesteruk
 
Introduction to Programming Bots
Dmitri Nesteruk
 
Converting Managed Languages to C++
Dmitri Nesteruk
 
Monte Carlo C++
Dmitri Nesteruk
 
Tpl DataFlow
Dmitri Nesteruk
 
YouTrack: Not Just an Issue Tracker
Dmitri Nesteruk
 
Проект X2C
Dmitri Nesteruk
 
Domain Transformations
Dmitri Nesteruk
 
Victor CG Erofeev - Metro UI
Dmitri Nesteruk
 
Developer Efficiency
Dmitri Nesteruk
 
Distributed Development
Dmitri Nesteruk
 
Dynamics CRM Data Integration
Dmitri Nesteruk
 
Web mining
Dmitri Nesteruk
 
Data mapping tutorial
Dmitri Nesteruk
 
Reactive Extensions
Dmitri Nesteruk
 
Design Patterns in .Net
Dmitri Nesteruk
 
Metaprogramming
Dmitri Nesteruk
 
Ad

Recently uploaded (20)

PDF
Human-centred design in online workplace learning and relationship to engagem...
Tracy Tang
 
PDF
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
PPT
Interview paper part 3, It is based on Interview Prep
SoumyadeepGhosh39
 
PDF
July Patch Tuesday
Ivanti
 
PDF
NewMind AI - Journal 100 Insights After The 100th Issue
NewMind AI
 
PPTX
MSP360 Backup Scheduling and Retention Best Practices.pptx
MSP360
 
PDF
DevBcn - Building 10x Organizations Using Modern Productivity Metrics
Justin Reock
 
PDF
Blockchain Transactions Explained For Everyone
CIFDAQ
 
PDF
SFWelly Summer 25 Release Highlights July 2025
Anna Loughnan Colquhoun
 
PDF
NewMind AI Journal - Weekly Chronicles - July'25 Week II
NewMind AI
 
PPTX
UiPath Academic Alliance Educator Panels: Session 2 - Business Analyst Content
DianaGray10
 
PDF
HCIP-Data Center Facility Deployment V2.0 Training Material (Without Remarks ...
mcastillo49
 
PDF
Smart Trailers 2025 Update with History and Overview
Paul Menig
 
PDF
Achieving Consistent and Reliable AI Code Generation - Medusa AI
medusaaico
 
PDF
Exolore The Essential AI Tools in 2025.pdf
Srinivasan M
 
PPTX
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 
PPTX
AUTOMATION AND ROBOTICS IN PHARMA INDUSTRY.pptx
sameeraaabegumm
 
PDF
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
PDF
Windsurf Meetup Ottawa 2025-07-12 - Planning Mode at Reliza.pdf
Pavel Shukhman
 
PPTX
Building a Production-Ready Barts Health Secure Data Environment Tooling, Acc...
Barts Health
 
Human-centred design in online workplace learning and relationship to engagem...
Tracy Tang
 
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
Interview paper part 3, It is based on Interview Prep
SoumyadeepGhosh39
 
July Patch Tuesday
Ivanti
 
NewMind AI - Journal 100 Insights After The 100th Issue
NewMind AI
 
MSP360 Backup Scheduling and Retention Best Practices.pptx
MSP360
 
DevBcn - Building 10x Organizations Using Modern Productivity Metrics
Justin Reock
 
Blockchain Transactions Explained For Everyone
CIFDAQ
 
SFWelly Summer 25 Release Highlights July 2025
Anna Loughnan Colquhoun
 
NewMind AI Journal - Weekly Chronicles - July'25 Week II
NewMind AI
 
UiPath Academic Alliance Educator Panels: Session 2 - Business Analyst Content
DianaGray10
 
HCIP-Data Center Facility Deployment V2.0 Training Material (Without Remarks ...
mcastillo49
 
Smart Trailers 2025 Update with History and Overview
Paul Menig
 
Achieving Consistent and Reliable AI Code Generation - Medusa AI
medusaaico
 
Exolore The Essential AI Tools in 2025.pdf
Srinivasan M
 
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 
AUTOMATION AND ROBOTICS IN PHARMA INDUSTRY.pptx
sameeraaabegumm
 
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
Windsurf Meetup Ottawa 2025-07-12 - Planning Mode at Reliza.pdf
Pavel Shukhman
 
Building a Production-Ready Barts Health Secure Data Environment Tooling, Acc...
Barts Health
 

Design Pattern Observations

  • 1. Observations on the Implementation of Design Patterns in C# and .NET Dmitri Nesteruk @dnesteruk
  • 2. Why design patterns? Design patterns are no longer as fashionable Still relevant, translated to most OOP languages We assume everyone knows them Made a video course on them (book might happen) Design pattern and architecture- related observations
  • 3. Local Inversion of Control Normal control: x.foo(y) Inverted control: y.foo(x) Implemented using e.g. extension methods
  • 4. Names.Add(name); “Names should add to itself the name” name.AddTo(Names); “Take name and add to Names”
  • 5. public static T AddTo<T>( this T self, ICollection<T> c) { c.Add(self); return self; }
  • 7. op == "AND" || op == "OR" || op == "XOR" Operation is AND or OR or XOR new[]{"AND","OR","XOR"}.Contains(op) This list of operations contains our operation (ugly) op.IsOneOf("AND","OR","XOR") Operation is one of the following
  • 8. public static bool IsOneOf<T>( this T self, params T[] items) { return items.Contains(self); }
  • 9. Composite Exposing collections and scalar objects in a uniform way Different scales: Properties Entire objects
  • 10. Property Composite I have names {FirstName, MiddleName, LastName} Sometimes, I want an individual name person.FirstName Sometimes, I want to print the full name string.Join(" ", person.Names) How do I get person.Names?
  • 11. public class Person { string FirstName, … { get; } public IEnumerable<string> Names { yield return FirstName; … } }
  • 12. Array-Backed Properties Suppose I want to add Title before the names… How should I expose it? Why not store names contiguously? Never accidentally fail to yield a name from Names Easier serialization (never miss a property) Many aggregate get-only properties (e.g., full name without title)
  • 13. public class Person { private string names[4]; public string Title { get { return names[0]; } set { names[0] = value; } } public string FullNameNoTitle => names.Skip(1).Join(' '); }
  • 14. Composite at Class Scale Neural network model A single neuron can be connected to another neuron A bunch of neurons form a layer We want all forms of entities to be connectable
  • 16. class Neuron { public List<Neuron> In, Out; public void ConnectTo(Neuron other) { Out.Add(other); other.In.Add(this); } }
  • 17. public class NeuronLayer : Collection<Neuron> {}
  • 18. var neuron1 = new Neuron(); var neuron2 = new Neuron(); var layer1 = new NeuronLayer(); var layer2 = new NeuronLayer(); neuron1.ConnectTo(neuron2); neuron1.ConnectTo(layer1); layer2.ConnectTo(neuron1); layer1.ConnectTo(layer2);
  • 19. Hot to make a single ConnectTo()? Cannot make a base class: NeuronLayer already has one Use a common interface NeuronLayer is an IEnumerable<Neuron> So why not make Neuron IEnumerable<Neuron> too?
  • 20. class Neuron : IEnumerable<Neuron> { public List<Neuron> In, Out; public void ConnectTo(Neuron other) { Out.Add(other); other.In.Add(this); } }
  • 21. public class Neuron : IEnumerable<Neuron> { public List<Neuron> In, Out; public IEnumerator<Neuron> GetEnumerator() { yield return this; } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } }
  • 22. public static void ConnectTo( this IEnumerable<Neuron> self, IEnumerable<Neuron> other) { if (ReferenceEquals(self, other)) return; foreach (var from in self) foreach (var to in other) { from.Out.Add(to); to.In.Add(from); } }
  • 23. var neuron1 = new Neuron(); var neuron2 = new Neuron(); var layer1 = new NeuronLayer(); var layer2 = new NeuronLayer(); neuron1.ConnectTo(neuron2); neuron1.ConnectTo(layer1); layer2.ConnectTo(neuron1); layer1.ConnectTo(layer2);
  • 24. Dynamic in Design Patterns Runtime-constructed Null Object Dynamic Proxy Dynamic Visitor
  • 25. Null Object A no-op object that can be injected when required Typically conforms to an interface We might not want to explicitly construct such an object (e.g., for testing) Dynamic to the rescue!
  • 26. public interface ILog { void Info(string msg); void Warn(string msg); } class ConsoleLog : ILog { public void Info(string msg) { WriteLine(msg); } ⋮ }
  • 27. public class BankAccount { private ILog log; private int balance; public BankAccount(ILog log) { this.log = log; } public void Deposit(int amount) { balance += amount; log.Info( $"Deposited ${amount}, balance is now {balance}"); } }
  • 28. Problem We have a hard dependency on ILog We cannot supply null – too many NREs We cannot rewrite existing code to use ?. everywhere Log may be passed on to other components How to make a log that does nothing?
  • 29. sealed class NullLog : ILog { public void Info(string msg) {} public void Warn(string msg) {} }
  • 30. public class Null<T> : DynamicObject where T:class { ⋮ }
  • 31. override bool TryInvokeMember( InvokeMemberBinder binder, object[] args, out object result) { result = Activator.CreateInstance( binder.ReturnType); return true; }
  • 32. public static T Instance { get { // ImpromptuInterface return new Null<T>().ActLike<T>(); } }
  • 33. var log = Null<ILog>.Instance; var ba = new BankAccount(log);
  • 34. Dynamic Visitor Dispatch = how many pieces of info do I need to know what to call? Static dispatch = all information must be known at compile time  Then what’s the point of polymorphism?
  • 35. interface IStuff { } class Foo : IStuff { } class Bar : IStuff { } static void f(Foo foo) { } static void f(Bar bar) { } IStuff i = new Foo(); f(i); // cannot resolve // call needs to be on i
  • 36. public abstract class Expression { public abstract void Accept(IExpressionVisitor visitor); } public interface IExpressionVisitor { void Visit(DoubleExpression de); void Visit(AdditionExpression ae); } public class DoubleExpression : Expression { override void Accept(IExpressionVisitor visitor) { visitor.Visit(this); } } // f⋆⋆⋆ this, too much work!
  • 37. interface IStuff { } class Foo : IStuff { } class Bar : IStuff { } static void f(Foo foo) { } static void f(Bar bar) { } IStuff i = new Foo(); f((dynamic)i); // woo-hoo! // dynamic dispatch!
  • 38. Dynamic Proxy Null Object: remove logging from entity Dynamic Proxy: add logging to entity (at runtime!) Implementations of Null<T> and Log<T> are almost identical…
  • 39. public class Log<T> : DynamicObject where T : class, new() { private readonly T subject; private Dictionary<string, int> methodCallCount = new Dictionary<string, int>(); protected Log(T subject) { this.subject = subject; } ⋮
  • 40. public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { try { // logging WriteLine($"Invoking {subject.GetType().Name}.{binder.Name} ([{string.Join(",", args)}])"); // more logging if (methodCallCount.ContainsKey(binder.Name)) methodCallCount[binder.Name]++; else methodCallCount.Add(binder.Name, 1); result = subject.GetType().GetMethod(binder.Name).Invoke(subject, args); return true; } catch { result = null; return false; } }
  • 41. public static I As<I>() where I : class { // ensure I is an interface return new Log<T>(new T()) .ActLike<I>(); }
  • 42. public string Info { get { var sb = new StringBuilder(); foreach (var kv in methodCallCount) sb.AppendLine($"{kv.Key} called {kv.Value} time(s)"); return sb.ToString(); } } // will not be proxied automatically public override string ToString() { return $"{Info}{subject}"; }
  • 43. var ba = Log<BankAccount>.As<IBankAccount>(); ba.Deposit(100); ba.Withdraw(50); WriteLine(ba); // ToString() // DynamicObject overrides :(
  • 44. That’s it! Questions? Answers? Hate mail? @dnesteruk Design Patterns in .NET online course at http://bit.ly/2p3aZww ImpromptuInterface: https://github.com/ekonbenefits/impromptu-interface