When ThingC()
is a Property:
var s = classA.classB.SomeValue;
var s = classA.SomeValue;
Add property SomeValue
to ClassA
and have it fetch the value from classB.SomeValue;
.
In other words, make it the responsibility of ClassA
to give you access to SomeValue
.
This gets rid of class Program
’s dependency on ClassB
.
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | using System.ComponentModel; using System.Runtime.CompilerServices; namespace ClassAClassBThingC { class Program { static void Main( string [] args) { ClassA classA = new ClassA(); var s = classA.classB.SomeValue; } } class ClassA { public ClassB classB = new ClassB(); } class ClassB : INotifyPropertyChanged { private string someValue = "Hello World!" ; public string SomeValue { get { return someValue; } set { if (someValue != value) { someValue = value; NotifyPropertyChanged(); } } } public event PropertyChangedEventHandler PropertyChanged; protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "" ) { this .PropertyChanged?.Invoke( this , new PropertyChangedEventArgs(propertyName)); } } } |
using System.ComponentModel; using System.Runtime.CompilerServices; namespace ClassAClassBThingC { class Program { static void Main(string[] args) { ClassA classA = new ClassA(); var s = classA.classB.SomeValue; } } class ClassA { public ClassB classB = new ClassB(); } class ClassB : INotifyPropertyChanged { private string someValue = "Hello World!"; public string SomeValue { get { return someValue; } set { if (someValue != value) { someValue = value; NotifyPropertyChanged(); } } } public event PropertyChangedEventHandler PropertyChanged; protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "") { this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
Notice line 12.
The refactored code looks like:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | using System.ComponentModel; using System.Runtime.CompilerServices; namespace ClassAClassBThingC { class Program { static void Main( string [] args) { ClassA classA = new ClassA(); var s = classA.SomeValue; } } class ClassA { public ClassB classB = new ClassB(); public string SomeValue { get { return classB.SomeValue; } set { classB.SomeValue = value; } } } class ClassB : INotifyPropertyChanged { private string someValue = "Hello World!" ; public string SomeValue { get { return someValue; } set { if (someValue != value) { someValue = value; NotifyPropertyChanged(); } } } public event PropertyChangedEventHandler PropertyChanged; protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "" ) { this .PropertyChanged?.Invoke( this , new PropertyChangedEventArgs(propertyName)); } } } |
using System.ComponentModel; using System.Runtime.CompilerServices; namespace ClassAClassBThingC { class Program { static void Main(string[] args) { ClassA classA = new ClassA(); var s = classA.SomeValue; } } class ClassA { public ClassB classB = new ClassB(); public string SomeValue { get { return classB.SomeValue; } set { classB.SomeValue = value; } } } class ClassB : INotifyPropertyChanged { private string someValue = "Hello World!"; public string SomeValue { get { return someValue; } set { if (someValue != value) { someValue = value; NotifyPropertyChanged(); } } } public event PropertyChangedEventHandler PropertyChanged; protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "") { this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
Notice how class Program
no longer has a reference to ClassB
.
Class Program
is no longer dependent on ClassB
.
This is a common occurrance which happens as programs grow. A programmer wants to get a value, the programmer knows where the value is, so the programmer just reaches through a circuitous route to get the value. It's fast and it gets results. So go ahead and do it if you're just playing with code to see if you can get something that works; however, be aware that this will need to be refactored out.
Now notice that ClassA
creates an instance of ClassB
and holds on to it.
Another optional refactoring we can do is pass and instance of ClassB
into
ClassA
so ClassA
doesn't have to create it.
This is known as "Dependency Injection."
Whenever you see a class creating and storing a reference to another class, consider the possibility of passing the class in as a constructor parameter instead. This tends to make the class easier to unit test.
Let's do that here. In the Main program
create ClassB
and pass it as a parameter to the ClassA
constructor:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | using System.ComponentModel; using System.Runtime.CompilerServices; namespace ClassAClassBThingC { class Program { static void Main( string [] args) { ClassB classB = new ClassB(); ClassA classA = new ClassA(classB); var s = classA.SomeValue; } } class ClassA { public ClassB classB; public ClassA(ClassB classB) { this .classB = classB; } public string SomeValue { get { return classB.SomeValue; } set { classB.SomeValue = value; } } } class ClassB : INotifyPropertyChanged { private string someValue = "Hello World!" ; public string SomeValue { get { return someValue; } set { if (someValue != value) { someValue = value; NotifyPropertyChanged(); } } } public event PropertyChangedEventHandler PropertyChanged; protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "" ) { this .PropertyChanged?.Invoke( this , new PropertyChangedEventArgs(propertyName)); } } } |
using System.ComponentModel; using System.Runtime.CompilerServices; namespace ClassAClassBThingC { class Program { static void Main(string[] args) { ClassB classB = new ClassB(); ClassA classA = new ClassA(classB); var s = classA.SomeValue; } } class ClassA { public ClassB classB; public ClassA(ClassB classB) { this.classB = classB; } public string SomeValue { get { return classB.SomeValue; } set { classB.SomeValue = value; } } } class ClassB : INotifyPropertyChanged { private string someValue = "Hello World!"; public string SomeValue { get { return someValue; } set { if (someValue != value) { someValue = value; NotifyPropertyChanged(); } } } public event PropertyChangedEventHandler PropertyChanged; protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "") { this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }