当我在C#中使用显式接口实现时,通常需要将对象转换为其接口之一以访问该接口的成员。由于编译时类型检查提供了更高的可靠性和可维护性,我始终倾向于使用隐式转换来执行此操作。我知道这样做的唯一方法涉及两行代码,并在范围中引入另一个变量。以下是一个例子:
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());
}
}
因为编译器知道 MyType
实现IMyType
我认为隐式转换比明确转换更好,因为稍后更改{{1}的声明在运行时将导致编译错误而不是MyType
。但是,我有点喜欢显式转换语法的简单性,并且经常看到它在其他人的代码中使用。
我的问题有三个:
答案 0 :(得分:2)
这是一个编译时选中的一个班轮:
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();
}
}
答案 1 :(得分:1)
作为对所有三个问题的回答:依靠隐式演员作为一般规则。您正在针对接口进行编程,而不是实现。
至于最后一个,如果你真的必须依赖于对一个实现(一个特定的派生类)的编程,那么在尝试对它做任何事情之前,确保该对象可以被强制转换。像这样:
var IMyType item3 = item as MyConcreteType;
if(item3 != null) {
item3.SayHello();
}
答案 2 :(得分:0)
如果您不确定该对象是否为该接口的实例,则执行as / null检查。通常,您从方法/函数调用返回一个接口,在这种情况下,您只需将其存储在没有强制转换的变量中(尽管可能仍需要进行null检查)。
答案 3 :(得分:-1)
我通常喜欢它:
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... */ }
}
}