Important Note
Friends, I would appreciate if you leave me a comment describing what you liked or did not like about this article.
Introduction
In Implementing Adapter Pattern and Imitated Multiple Inheritance in C# using Roslyn based VS Extension I presented a way of imitating multiple inheritance in C# using Roslyn based single file generator. The method of simulating multiple inheritance was based on the one described in Simulated Multiple Inheritance Pattern for C# article except that the 'sub-class' wrappers were automatically generated using a visual studio extension presented in that article.
I had this idea of implementing Multiple Inheritance using code generation long ago but only Roslyn allowed its implementation. Before Roslyn there were no tools available for analysing the code and pulling all the information required for wrapper generation within the Visual Studio extensions - there were some proprietary solutions, of course, e.g. the resharper, but they were not avaible for everyone. With Roslyn, however, sky is the limit of what can be achieved. My wrapper generators might just be a tip of an iceberg of what will be coming.
Several commenters to my previous article were upset that I call the resulting pattern 'Imitated Multiple Inheritance'. They were arguing that the resulting constructs are not polymorphic.
One of the aims of this article is precisely to show how to achieve Multiple Inheritance Polymorphism using the generated code and with the help of the interfaces.
The main purpose of this article is to show how by using Roslyn generated Multiple Inheritance and Adapter patterns you can improve the separation of concerns and code reuse.
Roslyn integration with Visual Studio comes only with VS 2015 Preview - so this is what you need to use to run the article's samples.
Last time I tried to upload the whole code at ones and the codeproject did not allow me, so now. I splitted the source code into smaller chunks - project by project.
The capabilities of the Visual Studio Extension NP.WrapperGenerator.vsix have been expanded to include another type of event wrapping (I call it One Way Event Wrapping) which will be explained a little further in the article.
In this installment I'll give a review of the wrapper generation, discuss implementing polymorphic 'multiple inheritance' using interface, and describe One Way Event Wrapping.
In the next installment of this article I plan to provide some more striking WPF based samples of polymorphic multiple inheritance and also to provide a sample of (in)famous diamond inheritance implemented in C++ by using virtual
keyword.
Installing the Visual Studio Extension NP.WrapperGenerator.vsix
In order to be able to work through the samples below, you need to install NP.WrapperGenerator.vsix extension that comes within VSIS.zip file. All you need to do to install it - is to unzip the folder and double click the extension. After that you should restart your VS 2015 instances - in order for them to be able to use the new extension.
If you played with the samples of the previous article, you might have the previous version of this extensions installed. In that case, you need to uninstall it before installing the new version. In order to do it - go to "Tools->Extensions and Updates" menu item within any version instance of your VS 2015. Find WrapperGenerator extension (usually at the bottom), click on it and press "Uninstall" button.
Refresher
Here I give just a brief refresher of the previous article Implementing Adapter Pattern and Imitated Multiple Inheritance in C# using Roslyn based VS Extension in order for people to be able to read this article independently.
The Main Principles of Wrapper Generation with Inheritance Analogies
As was described in the previous article - the NP.WrapperGenerator.vsix extension can be used for generating a partial class file containing the wrappers around properties, events and methods of some other classes. We use class attributes to specify which wrappers should be generated and the "Custom Tool" property of the file that contains those attributes should be set to "WrapperFileCodeGenerator".
The class attributes allow also changing the names and encapsulation level of the wrapped class members, e.g. public property Name
can be wrapped as protected property PersonName
.
Wrapper Generation Sample
The purpose of this sample is to demonstrate the capabilities of NP.WrapperGenerator.vsix
extension.
The sample solution is located under WrapperGenerationSample folder.
The class to be wrapped is called Person
. It is a very simple class - containing two properties: Name
and Age
, one event NameChangedEvent
and one method - void ChangeName(string newName)
:
public class Person
{
string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
if (NameChangedEvent != null)
NameChangedEvent(this);
}
}
public int Age { get; set; }
public event Action<person> NameChangedEvent = null;
public void ChangeName(string newName)
{
Name = newName;
}
}
</person>
Class that wraps Person
is called PersonWrapper
. It is defined a partial, and it has a number of special class attributes that specify the wrapping:
[Wraps(typeof(Person), WrappedItemsKind.Property, "Name", "Age")]
[Wraps(typeof(Person), WrappedItemsKind.Event, "NameChangedEvent")]
[WrapsAndChanges(typeof(Person), WrappedItemsKind.Method, "ChangeName", "ChangePersonName", EncapsulationLevel.Internal)]
public partial class PersonWrapper
{
}
In order for wrapper generation to take place, "Custom Tool" of PersonWrapper.cs file should be eset to "WrapperFileCodeGenerator":
Once the "Custom Tool" property is set, or once PersonWrapper.cs file modified and saved, the NP.WrapperGenerator extension will produce a dependent file PersonWrapper.wrapper.cs
containing another part of this partial class with the wrappers:
Here is the content of PersonWrapper.wrapper.cs
file:
using System;
using WrapperGenerationSample;
namespace WrapperGenerationSample
{
public partial class PersonWrapper
{
private Person _person;
public static implicit operator Person (PersonWrapper objectToConvert)
{
return objectToConvert._person;
}
public event Action<person> NameChangedEvent
{
add { _person.NameChangedEvent += value; }
remove { _person.NameChangedEvent -= value; }
}
public Person ThePerson
{
get
{
return _person;
}
set
{
_person = value;
}
}
public String Name
{
get
{
return _person.Name;
}
set
{
_person.Name = value;
}
}
public Int32 Age
{
get
{
return _person.Age;
}
set
{
_person.Age = value;
}
}
internal void ChangePersonName(String newName)
{
_person.ChangeName(newName);
}
}
}
</person>
First of all it contains a public property ThePerson
of type Person
:
private Person _person;
...
public Person ThePerson
{
get
{
return _person;
}
set
{
_person = value;
}
}
This property represents an object to wrap. The ThePerson
object can be set in the constructor of the PersonWrapper
class - using the languate of inheritance, ThePerson
object represents the base
class of the PersonWrapper
and its setting it within the PersonWrapper
's constructor maps into calling base(...)
constructor of the base class.
The rest of the functionality of PersonWrapper.wrapper.cs class simply contains wrappers around ThePerson
object's properties, events and methods with an important exception of the implicit converter operator:
public static implicit operator Person (PersonWrapper objectToConvert)
{
return objectToConvert._person;
}
It converts PersonWrapper
object into Person
by simply returning the object referenced by ThePerson
property. This maps into implicit conversion of a sub-class into a super class.
Now, take a look at the class attributes above PersonWrapper
class. (These attrubtes, BTW require a reference to NP.WrapperAttrs.dll file located within WrapperGenerationSample/Dlls folder).
Wraps
attribute requires the type of the wrapped class (the superclass), the kind of class member being wrappers - property, event or method and a list of names of class members of that kind to be wrapped e.g. in our case it can be "Name" and "Age" properties or "NameChangedEvent" event:
[Wraps(typeof(Person), WrappedItemsKind.Property, "Name", "Age")]
[Wraps(typeof(Person), WrappedItemsKind.Event, "NameChangedEvent")]
WrapsAndChanges
attribute is more powerful - it allows to change the name and encapsulation level of the class member, but it only deals with one class member at a time - you cannot pass several members to it at once as we did above with "Name" and "Age":
[WrapsAndChanges(typeof(Person), WrappedItemsKind.Method, "ChangeName", "ChangePersonName", EncapsulationLevel.Internal)]
This attribute changes the name of ChangeName(...)
method to ChangePersonName(...)
and sets the wrapper's methods encapsulation level to internal
. BTW, if the encapsulation level is not specified it is going to be the same as that of the wrapped class member - not necessarily public
.
Example of usage of the PersonWrapper
class can be found within Program.cs file:
static void Main(string[] args)
{
PersonWrapper personWrapper = new PersonWrapper
{
ThePerson = new Person { Name = "John", Age = 30 }
};
personWrapper.NameChangedEvent += PersonWrapper_NameChangedEvent;
personWrapper.ChangePersonName("Johnathan");
}
private static void PersonWrapper_NameChangedEvent(Person obj)
{
Console.WriteLine(obj.Name);
}
Discussion About Inheritance and Multiple Inheritance
Some commentators to my previous article thought that the wrapper generation presented above has nothing to do with the inheritance.
In fact this is exactly how class inheritance is implemented by the compilers - they create objects of superclass and provide the wrappers around them, only they do it in the binary code and I am forced to do the code generation.
Other readers were concerned that the resulting 'sub-classes' are not polymorphic - i.e. they cannot be used in place of their 'super-classes'. One can use the interfaces, however, to fix this problem as we are going to show below.
There are some limitations to this type of inheritance, however:
- This type of inheritance cannot have virtual functions used in 'super-class' overridden in 'sub-class'. The C# does not allow me to change the function pointers so creating virtual functions would requre a more invasive - binary code generation approach.
- And a related issue is that this inheritance does not allow using correct
this
pointer within 'super-classes' - this
within a 'super-class' will be the wrapped object, not the wrapper object. This is not a big deal when it comes to properties or methods - since the properties and methods of a 'super-class' should not know about the 'sub-class' anyways. But it can create a big problem when it comes to the events containing this
pointer as an argument. "One Way" event wrapping described below will show how to get around this problem.
In general, in spite of these two limitations this type of inhertiance can be very useful, as I hope to prove to you below.
In the "Refresher" sample above, we had PersonWrapper
class 'inheriting' from Person
class - which is a single class inhertitance. Nothing, however, prevents us from using several 'base' classes thus imitating multiple inheritance as the sample below are going to show.
Simple Multiple Inheritance with Polymorphism Sample
The purpose of this sample is to show how Polymorphism can be implemented using our inheritance and interfaces.
The sample code is located under SimplePolymorphism
solution.
The main project contains two very simple interfaces IPerson
and ISelectable
:
public interface IPerson
{
string Name { get; set; }
void PrintInfoToConsole();
}
public interface ISelectable
{
bool IsItemSelected { get; set; }
event Action<iselectable> ItemSelectedChangedEvent;
}
</iselectable>
There are two (also very simple) implementations of these two interfaces: Person
and Selectable
correspondingly. In particular the implementation of Person
's PrintInfoToConsol()
method, prints the line "Name = ", where "" should be replaced by the Name
property of Person
object:
public void PrintInfoToConsole()
{
Console.WriteLine("Name = " + Name);
}
Static method Program.PrintPersonInfoToConsol(IPerson person)
of the main Program
class calls PrintInfoToConsole()
method of the IPerson
object passed to it:
static void PrintPersonInfoToConsole(IPerson person)
{
person.PrintInfoToConsole();
}
Here is the definition of the wrapper class SelectablePerson
(extends - in our sense - classes Person
and Selectable
):
[Wraps(typeof(Selectable), WrappedItemsKind.Event, "ItemSelectedChangedEvent")]
[Wraps(typeof(Selectable), WrappedItemsKind.Property, "IsItemSelected")]
[Wraps(typeof(Selectable), WrappedItemsKind.Method, "ToggleIsSelected")]
[Wraps(typeof(Person), WrappedItemsKind.Property, "Name")]
[Wraps(typeof(Person), WrappedItemsKind.Method, "PrintInfoToConsole")]
public partial class SelectablePerson : IPerson, ISelectable
{
}
As you can see the generated wrapper members also make it implement IPerson
and ISelectable
interfaces. As an IPerson
objects of this class can be passed to Program.PrintPersonInfoToConsol(IPerson person)
method.
Take a look at Program
class - we create a SelectablePerson
object and pass it to Program.PrintPersonInfoToConsol(IPerson person)
method:
SelectablePerson selectablePerson = new SelectablePerson
{
ThePerson = new Person { Name = "Joe" },
TheSelectable = new Selectable()
};
PrintPersonInfoToConsole(selectablePerson);
As expected, when running the code above, we'll get "Name = Joe" printed to the console.
What if we want to create another class implementing IPerson
and ISelectable
with a different implementation of its PrintInfoToConsole()
method - say instead of printing "Name = Joe" it will have to print "Hello Joe". Class SelectablePersonWithModifiedMethod
shows how to do it:
[Wraps(typeof(Selectable), WrappedItemsKind.Event, "ItemSelectedChangedEvent")]
[Wraps(typeof(Selectable), WrappedItemsKind.Property, "IsItemSelected")]
[Wraps(typeof(Selectable), WrappedItemsKind.Method, "ToggleIsSelected")]
[Wraps(typeof(Person), WrappedItemsKind.Property, "Name")]
public partial class SelectablePersonWithModifiedMethod : IPerson, ISelectable
{
public void PrintInfoToConsole()
{
Console.WriteLine("Hello " + this.Name);
}
}
We do not have a Wraps
attribute for PrintInfoToConsole()
method and instead provide its implement explicitly.
Creating such object and passing it to Program.PrintPersonInfoToConsole
method will result in "Hello Joe" printed:
SelectablePersonWithModifiedMethod selectablePersonWithModifiedMethod = new SelectablePersonWithModifiedMethod
{
ThePerson = new Person { Name = "Joe" },
TheSelectable = new Selectable()
};
PrintPersonInfoToConsole(selectablePersonWithModifiedMethod);
As you can see - interface polymorphism stands - the correct method is being called on the objects inherited in our sense.
One Way Event Wrapper Generation with this
Reference Substitution
For people who know WPF, one of the most inglorious examples of C# limitation is its inability to factor out the code related to defining and firing the PropertyChanged
event in the view models in a generic fashion. To be sure one can define a PropertyChangedImpl
class as following:
public class PropertyChangedImpl : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propName)
{
if (PropertyChanged == null)
return;
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
Then all of your View Models can inherit from PropertyChangedImpl
class. But because of the lack of Multiple Inheritance in C#, inhertiting PropertyChangedImpl
class will prevent you from inheriting from any other class so, many times you will decide that it is not worth and and simply copy and paste the PropertyChangedImpl
code.
In this section I describe how to mitigate this problem using wrapper generation inhertitance and also describe a new concept of One Way Event wrapper generation I stumbled upon because while figuring out how to make PropertyChangedImpl
inheritance work.
Take a look at PropertyChnagedWrapperSample
project. Its View Model MyViewModel
class contains only one property TheText
that calls method OnPropertyChanged
which is a wrapper over the same named method of PropertyChangedImpl
class:
[Wraps(typeof(PropertyChangedImpl), WrappedItemsKind.Event, "PropertyChanged")]
[Wraps(typeof(PropertyChangedImpl), WrappedItemsKind.Method, "OnPropertyChanged")]
public partial class MyViewModel : INotifyPropertyChanged
{
//public event PropertyChangedEventHandler PropertyChanged;
public MyViewModel()
{
this.ThePropertyChangedImpl = new PropertyChangedImpl();
//this.ThePropertyChangedImpl.PropertyChanged += ThePropertyChangedImpl_PropertyChanged;
}
//private void ThePropertyChangedImpl_PropertyChanged(object sender, PropertyChangedEventArgs e)
//{
// if (PropertyChanged != null)
// {
// PropertyChanged(this, e);
// }
//}
string _text = null;
public string TheText
{
get
{
return _text;
}
set
{
if (_text == value)
return;
_text = value;
OnPropertyChanged("TheText");
}
}
}
MainWindow.xaml file defined an instance of the View Model within its Resources
section and also also defines a TextBlock
above and a TextBox
below. Text
properties of the TextBlock
and TextBox
are both bound to TheText
property of the View Model so if the bindings work and PropertyChanged
event if firing properly, whatever is entered within the TextBox
should appear in the TextBlock
above:
<window.resources>
<local:myviewmodel x:key="TheViewModel">
</local:myviewmodel></window.resources>
<grid datacontext="{Binding Source={StaticResource TheViewModel}}">
<stackpanel horizontalalignment="Center" orientation="Vertical" verticalalignment="Center">
<textblock text="{Binding TheText}">
<stackpanel orientation="Horizontal">
<textblock text="Enter Text: ">
<textbox text="{Binding TheText, UpdateSourceTrigger=PropertyChanged}">
</textbox></textblock></stackpanel>
</textblock></stackpanel>
</grid>
If we run the project as it is, however, we'll notice that the TextBlock
above is not updated.
What is broken here is the PropertyChanged
event firing - in particular the handling of this
reference passed to it. Indeed OnPropertyChanged(...)
called on MyViewModel
class will call the OnPropertyChanged(...)
method of the wrapped PropertyChangedImpl
object, which will fire PropertyChanged
event on that object, passing to it this
reference with this
meaning PropertyChangedImpl
object and not the MyViewModel
wrapper:
PropertyChanged(this, new PropertyChangedEventArgs(propName));
Because of that, the binding - which is set on the MyViewModel
object does not notice the PropertyChanged
event firing.
There is a way to fix the problem, though: comment out the PropertyChanged
event's Wrap
attribute and uncomment all the commented out lines so that MyViewModel
class will look like this:
using NP.WrapperAttrs;
using System.ComponentModel;
namespace PropertyChangedWrapperSample
{
//[Wraps(typeof(PropertyChangedImpl), WrappedItemsKind.Event, "PropertyChanged")]
[Wraps(typeof(PropertyChangedImpl), WrappedItemsKind.Method, "OnPropertyChanged")]
public partial class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public MyViewModel()
{
this.ThePropertyChangedImpl = new PropertyChangedImpl();
this.ThePropertyChangedImpl.PropertyChanged += ThePropertyChangedImpl_PropertyChanged;
}
private void ThePropertyChangedImpl_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(this, e);
}
}
string _text = null;
public string TheText
{
get
{
return _text;
}
set
{
if (_text == value)
return;
_text = value;
OnPropertyChanged("TheText");
}
}
}
}
Try running the sample again after making those changes. Now everything works and when you type "Hello" in the TextBox
you will also see Hello
displayed above:
Let us take a look as what's happening here. Instead of MyViewModel.PropertyChanged
event being a perfect wrapper of PropertyChangedImpl.PropertyChanged
event, we define it to be a separate entity that is fired when PropertyChangedImpl.PropertyChanged
event is fired. Moreover we replace the first argument if the event with this
reference. Since this replacement is done within MyViewModel
class, the correct object is passed to it:
public MyViewModel()
{
this.ThePropertyChangedImpl = new PropertyChangedImpl();
this.ThePropertyChangedImpl.PropertyChanged += ThePropertyChangedImpl_PropertyChanged;
}
private void ThePropertyChangedImpl_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(this, e);
}
}
This is what I call One Way Event Wrapping with this
Reference Substitution (and if someone can come with a better and more succinct name - I'll be happy to consider it:-))
I added OneWayEventWraps
attribute and the functionality to generate One Way Event related wrappers into the new version of NP.WrapperGenerator.vsix
extension.
In order to see the new attribute in action, please take a look at PropertyChangedOneWayEventWrapSample
project. It is very similar to PropertyChnagedWrapperSample
project considered above. The only difference is that instead of code that we uncommented in MyViewModel
class we use OneWayEventWraps
extension. Here is how the MyViewModel
class looks now:
[OneWayEventWraps(typeof(PropertyChangedImpl), "PropertyChanged", "sender")]
[Wraps(typeof(PropertyChangedImpl), WrappedItemsKind.Method, "OnPropertyChanged")]
public partial class MyViewModel : INotifyPropertyChanged
{
public MyViewModel()
{
this.ThePropertyChangedImpl = new PropertyChangedImpl();
}
string _text = null;
public string TheText
{
get
{
return _text;
}
set
{
if (_text == value)
return;
_text = value;
OnPropertyChanged("TheText");
}
}
}
OneWayEventWraps
attribute takes the wrapped object ('base' class) as its first argument. Second argument is the name of the wrapped event - PropertyChanged
in our case. Third argument is optional (only if you want to replace this
reference) and it specifies the name of the event delegate's argument to replace with this
reference. In our case, the event's delegate is of type void (object sender, PropertyChangedEventArgs e)
, so we want to replace its argument called "sender" with this
reference.
Here is the resulting generated code from MyViewModel.wrapper.cs file - I only show parts relevant for the One Way Event wrapping (also I added some comments explaining the code):
...
// declare the PropertyChanged event within the wrapper class
public event PropertyChangedEventHandler PropertyChanged;
public PropertyChangedImpl ThePropertyChangedImpl
{
get
{
return _propertyChangedImpl;
}
set
{
if ((_propertyChangedImpl != null))
{
// remove event handler to the old _propertyChangedImpl.PropertyChanged -= _propertyChangedImpl_PropertyChanged;
}
_propertyChangedImpl = value;
if ((_propertyChangedImpl != null))
{
// added event handler to the new _propertyChangedImpl.PropertyChanged += _propertyChangedImpl_PropertyChanged;
}
}
}
// the event handler
private void _propertyChangedImpl_PropertyChanged(Object sender, PropertyChangedEventArgs e)
{
if ((PropertyChanged != null))
{
// replaced PropertyChanged(this, e);
}
}
...
As will be shown in part 2 of this article - there are many more uses of One Way Event Wrapping than just for PropertyChanged
event.
Conclusion
In this article we presented some cases of simple polymorphic wrapper-based imitated Multiple Inheritance and also talked about defined and presented One Way Event Wrapping.
Next installment of this article will talk about more complex cases of Multiple Inheritance polymorphism and about resolving the diamond Multiple Inheritance.