Title: Implement interfaces explicitly or implicitly in C#
Suppose you create a class and in the declaration you indicate that it implements one or more interfaces. If you right-click an interface's name, the dropdown displayed by Visual Studio includes an "Implement Interface" submenu. If you look at the picture on the right, you can see that this submenu has the options "Implement Interface" and "Implement Interface Explicitly."
(Depending on the layout of your windows, you may also see one of Microsoft's latest gratuitous changes: submenus that open to the left. It seems more than a little odd to have the submenu arrow point right but then have the submenu open on the left. And the change isn't system-wide so programs like Visual Studio are inconsistent with other programs in Windows. But whatever.)
If you select "Implement Interface," you get an implementation similar to the following.
public class Person : IComparable<Person>
{
public string FirstName, LastName;
#region IComparable<Person> Members
public int CompareTo(Person other)
{
throw new NotImplementedException();
}
#endregion
}
The code that Visual Studio added satisfies the interface. It also lets you invoke the CompareTo method directly from a Person object. For example, if person1 and person2 are Person objects, then you can call person1.CompareTo(person2). You can also use an IComparable<Person> to call CompareTo.
However, note that you cannot cast a Person into an IComparable. Visual Studio doesn't see a problem at design time or compile time, but the cast fails at run time.
The following code demonstrates these approaches.
// Make some Persons.
Person person1 = new Person();
Person person2 = new Person();
int result;
// Allowed.
result = person1.CompareTo(person2);
// Allowed.
result = ((IComparable<Person>)person1).CompareTo(person2);
// Allowed.
IComparable<Person> comparable = (IComparable<Person>)person1;
result = comparable.CompareTo(person2);
// Fails at run time.
IComparable comparable2 = (IComparable)person1;
result = comparable2.CompareTo(person2);
In contrast, if you right-click and use the menu to invoke the "Implement Interface Explicitly" command, you get the following implementation.
public class Person : IComparable<Person>
{
public string FirstName, LastName;
#region IComparable<Person> Members
int IComparable<Person>.CompareTo(Person other)
{
throw new NotImplementedException();
}
#endregion
}
This is similar to the previous version except the CompareTo method is prefixed with IComparable<Person>.. That prefix means the CompareTo method is only available to objects of type IComparable<Person> and not to objects of the class's type. The comments in the following code show the previous code handles the new implementation approach. Note that the cast to IComparable still fails at run time.
// Make some Persons.
Person person1 = new Person();
Person person2 = new Person();
int result;
// Not allowed.
result = person1.CompareTo(person2);
// Allowed.
result = ((IComparable<Person>)person1).CompareTo(person2);
// Allowed.
IComparable<Person> comparable = (IComparable<Person>)person1;
result = comparable.CompareTo(person2);
// Fails at run time.
IComparable comparable2 = (IComparable)person1;
result = comparable2.CompareTo(person2);
To summarize, implicit implementation gives you more flexibility because it lets you invoke the method from either an instance of the class or an instance of the interface. If you want that greater flexibility, use implicit implementation.
However, if you don't plan to invoke the interface's methods in your code, you may prefer to use an explicit implementation. That still allows whatever library you're using to call the method (for example, Array.Sort can still sort an array of Person object), but it hides the method from your code. That prevents you from calling the method accidentally and it keeps IntelliSense a little less cluttered.
Download the example to experiment with it and to see additional details.
|