OOPS概念:将对象引用传递给接口和在C#中创建类对象有什么区别?
我有一个类,OOPS概念:将对象引用传递给接口和在C#中创建类对象有什么区别?,c#,class,interface,C#,Class,Interface,我有一个类,CustomerNew,还有一个接口,iccustomer: public class CustomerNew : ICustomer { public void A() { MessageBox.Show("Class method"); } void ICustomer.A() { MessageBox.Show("Interface method"); } public void B(
CustomerNew
,还有一个接口,iccustomer
:
public class CustomerNew : ICustomer
{
public void A()
{
MessageBox.Show("Class method");
}
void ICustomer.A()
{
MessageBox.Show("Interface method");
}
public void B()
{
MessageBox.Show("Class Method");
}
}
public interface ICustomer
{
void A();
}
我对这两行代码感到非常困惑
ICustomer objnew = new CustomerNew();
CustomerNew objCustomerNew = new CustomerNew();
objnew.B(); // Why this is wrong?
objCustomerNew.B(); // This is correct because we are using object of class
第一行代码表示我们在objnew
中传递CustomerNew类的对象引用,对吗?如果是,那么为什么我不能使用接口objnew
访问类的方法B()
有人能详细解释一下这两个问题吗。在第一行:
ICustomer objnew
您正在指示编译器将objnew
视为iccustomer
,并且由于接口未声明B()
方法,因此它会出错
在第二行:
CustomerNew objCustomerNew
您将
objCustomerNew
称为CustomerNew
,因为它确实指定了B()
方法,所以它可以很好地编译。接口有许多特性和用法,但一个核心问题是能够在约定的合同中向外部世界展示功能
让我给你举个例子。考虑一下自动贩卖机。它有一两个插槽供您输入硬币,几个按钮供您选择正确类型的苏打水,还有一个按钮供您分配苏打水(除非选择按钮也这样做)
现在,这是一个接口。这隐藏了界面背后的机器复杂性,并为您提供了一些选择
但是,这里是重要的一部分,机器内部有很多功能,甚至可能有其他按钮和旋钮,通常在出现故障时,或者当维修人员不得不清空机器或将其装满苏打水时,维修人员可以测试或操作机器
机器的这一部分对您是隐藏的,您只能访问添加到该接口的外部接口的创建者
你甚至不知道机器在幕后是如何运作的。我可以创建一个新的自动售货机,将苏打水从附近的工厂传送进来,并将您添加的硬币直接传送到银行,这样您就不会更聪明了。更不用说我会很富有,但那是另一回事了
那么,回到你的代码
您明确地将objnew
声明为iccustomer
。你在这个界面后面放的任何东西都是隐藏的。您只能访问作为该接口一部分声明的任何内容
另一个变量被声明为具有基础对象的类型,因此您可以完全访问它的所有公共功能。可以把它想象成打开自动售货机的锁,在正面打开的情况下使用它。实际上,接口也是一种类型(你不能创建接口实例,因为它们只是元数据) 由于
CustomerNew
实现了iccustomer
,因此可以将CustomerNew
的实例升级到iccustomer
。当iccustomer
被键入为iccustomer
时,您只能访问iccustomer
成员
这是因为C#是一种强类型语言,因此,为了访问特定成员(即方法、属性、事件…),您需要一个对象引用,该引用由定义要访问的成员的类型限定(即,您需要将CustomerNew
对象存储在CustomerNew
类型的引用中,以访问方法B
)
更新
OP说:
因此,由于向上转换,我们只能访问内部的方法
界面,对吗?向上投射是这背后的主要原因
是的。一个简单的解释是,实现iccustomer
的对象不应强制为CustomerNew
。您需要向下转换iccustomer
对CustomerNew
的引用,以便能够访问CustomerNew
成员
由于类和接口都是类型,而C#是强类型语言,因此可以通过提供对象的实际类型来访问对象成员。这就是为什么需要使用类型转换
例如,您的代码执行隐式向上转换:
// This is an implicit cast that's equivalent to
// ICustomer objnew = (ICustomer)new CustomerNew()
ICustomer objnew = new CustomerNew();
隐式向上转换是可能的,因为编译器已经知道CustomerNew
实现iccustomer
内省CustomerNew
元数据,而您不能隐式向下转换iccustomer
引用,因为谁知道谁实现了iccustomer
?它可以是CustomerNew
或任何其他类或结构:
ICustomer asInterface = new CustomerNew();
// ERROR: This won't compile, you need to provide an EXPLICIT DOWNCAST
CustomerNew asClass1 = asInterface;
// OK. You're telling the compiler you know that asInterface
// reference is guaranteed to be a CustomerNew too!
CustomerNew asClass2 = (CustomerNew)asInterface;
如果您不确定iccustomer
是否为CustomerNew
,可以使用as
操作符,如果无法进行强制转换,该操作符在运行时不会引发异常:
// If asInterface isn't also a CustomerNew, the expression will set null
CustomerNew asClass3 = asInterface as CustomerNew;
您的
objnew
变量是对实现iccustomer
的对象的引用。请注意,这可能是任何对象,只要它实现iccustomer
。因此此引用公开的所有内容都是iccustomer的成员,而iccustomer只是方法a()
在您的示例中
如果您确实希望访问对象的B()
方法,该对象由objnew
引用,则必须将其显式转换为CustomerNew
引用(这是C#的工作安全类型),例如:
CustomerNew objCustomerNew = objnew as CustomerNew;
objCustomerNew.B();
或
请记住,
objnew
可以是实现iccustomer
的任何类型,因此如果以后实现其他iccustomer
类,则转换objnew为CustomerNew
可以解析为null
。这与编译时间有关(即静态)类型检查。如果你看这两行
ICustomer objnew = new CustomerNew();
objnew.B();
您可以清楚地看到,objnew
引用的对象有一个B()
方法,因此您知道第二行在运行时不会有问题
但是,编译器并不是这样看待它的
ICustomer objnew = new CustomerNew();
objnew.B();
ICustomer objnew = new CustomerNew();
if( some complicated expression ) objnew = new CustomerOld() ;
objnew.B();
void f( ICustomer objnew ) {
objnew.B();
}
public interface IMyInterface
{
}
public class MyBaseClass:IMyInterface
{
public string B()
{
return "In Abstract";
}
}
public class MyDerivedClass : MyBaseClass
{
}
MyBaseClass inst = new MyDerivedClass();
inst.B(); //Works fine
MyDerivedClass inst1 = new MyDerivedClass();
inst1.B(); //Works fine
IMyInterface inst2 = new MyDerivedClass();
inst2.B(); //Compile time error