Safe & Simple Access to Explicit Interface Members in C#
When I am working with explicit interface implementations in C#, it often becomes necessary to cast an object to one of its interfaces in order to access a member of that interface. Because of the improved reliability and maintainability afforded by compile time type checking, I have always preferred to use implicit conversions to perform this. The only way I know of to do this involves two lines of code and introduces another variable into the scope. Below is an exa开发者_C百科mple:
public interface IMyType
{
string SayHello();
}
public class MyType : IMyType
{
string IMyType.SayHello() { return "Hello!"; }
}
class Program
{
static void Main(string[] args)
{
var item = new MyType();
// Option 1 - Implicit cast. Compile time checked but takes two lines.
IMyType item2 = item;
System.Console.WriteLine(item2.SayHello());
// Option 2 - One line but risks an InvalidCastException at runtime if MyType changes.
System.Console.WriteLine(((IMyType)item).SayHello());
// Option 3 - One line but risks a NullReferenceException at runtime if MyType changes.
System.Console.WriteLine((item as IMyType).SayHello());
}
}
Because the compiler knows that MyType
implements IMyType
I assume that an implicit cast is better than an explicit one since a later change to the declaration of MyType
will result in a compile error instead of an InvalidCastException
at runtime. However, I somewhat prefer the simplicity of the explicit cast syntax and have often seen it used in other people's code.
My question is threefold:
- Which of the above options do you prefer (and why)?
- Is there a better way to do this?
- What are some best practices regarding performing explicit casts when implicit casts are possible?
Here is a compile-time checked one liner:
public static class Converter
{
public static T ReturnAs<T>(T item)
{
return item;
}
}
class Program
{
static void Main(string[] args)
{
var item = new MyType();
// Option 1 - Implicit cast. Compile time checked but takes two lines.
IMyType item2 = item;
System.Console.WriteLine(item2.SayHello());
// Option 2 - One line but risks an InvalidCastException at runtime if MyType changes.
System.Console.WriteLine(((IMyType)item).SayHello());
// Option 3 - One line but risks a NullReferenceException at runtime if MyType changes.
System.Console.WriteLine((item as IMyType).SayHello());
// Option 4 - compile time one liner
Converter.ReturnAs<IMyType>(item).SayHello();
}
}
As an answer to all three questions: Rely on implicit casts as a general rule. You're programming against the interface, not the implementation.
As for the last one, if you really must rely on programming against an implementation (a specific derived class) then make sure the object can be cast the type before attempting to do anything with it. Something like this:
var IMyType item3 = item as MyConcreteType;
if(item3 != null) {
item3.SayHello();
}
If you're not sure that the object is an instance of the interface then do an as/null check. Usually you're returning an interface from a method/function call in which case you just store it in a variable without a cast (though the null check may still be necessary).
I usually like it as:
class Program
{
static void Main(string[] args)
{
var item = new MyType();
if( item is IMyType ){
Console.WriteLine( (item as IMyType).SayHello() );
}
else { /* Do something here... */ }
}
}
精彩评论