Interface Basics
suggest changeAn Interface’s function known as a “contract” of functionality. It means that it declares properties and methods but it doesn’t implement them.
So unlike classes Interfaces:
- Can’t be instantiated
- Can’t have any functionality
- Can only contain methods * (Properties and Events are methods internally)
- Inheriting an interface is called “Implementing”
- You can inherit from 1 class, but you can “Implement” multiple Interfaces
public interface ICanDoThis{
void TheThingICanDo();
int SomeValueProperty { get; set; }
}
Things to notice:
- The “I” prefix is a naming convention used for interfaces.
- The function body is replaced with a semicolon “;”.
- Properties are also allowed because internally they are also methods
public class MyClass : ICanDoThis {
public void TheThingICanDo(){
// do the thing
}
public int SomeValueProperty { get; set; }
public int SomeValueNotImplemtingAnything { get; set; }
}
.
ICanDoThis obj = new MyClass();
// ok
obj.TheThingICanDo();
// ok
obj.SomeValueProperty = 5;
// Error, this member doesn't exist in the interface
obj.SomeValueNotImplemtingAnything = 5;
// in order to access the property in the class you must "down cast" it
((MyClass)obj).SomeValueNotImplemtingAnything = 5; // ok
This is especially useful when you’re working with UI frameworks such as WinForms or WPF because it’s mandatory to inherit from a base class to create user control and you loose the ability to create abstraction over different control types. An example? Coming up:
public class MyTextBlock : TextBlock {
public void SetText(string str){
this.Text = str;
}
}
public class MyButton : Button {
public void SetText(string str){
this.Content = str;
}
}
The problem proposed is that both contain some concept of “Text” but the property names differ. And you can’t create create a abstract base class because they have a mandatory inheritance to 2 different classes. An interface can alleviate that
public interface ITextControl{
void SetText(string str);
}
public class MyTextBlock : TextBlock, ITextControl {
public void SetText(string str){
this.Text = str;
}
}
public class MyButton : Button, ITextControl {
public void SetText(string str){
this.Content = str;
}
public int Clicks { get; set; }
}
Now MyButton and MyTextBlock is interchangeable.
var controls = new List<ITextControls>{
new MyTextBlock(),
new MyButton()
};
foreach(var ctrl in controls){
ctrl.SetText("This text will be applied to both controls despite them being different");
// Compiler Error, no such member in interface
ctrl.Clicks = 0;
// Runtime Error because 1 class is in fact not a button which makes this cast invalid
((MyButton)ctrl).Clicks = 0;
/* the solution is to check the type first.
This is usually considered bad practice since
it's a symptom of poor abstraction */
var button = ctrl as MyButton;
if(button != null)
button.Clicks = 0; // no errors
}