尝试从接口调用方法会导致错误“需要对象引用”
本文关键字:错误 对象引用 接口 调用 方法 | 更新日期: 2023-09-27 18:12:17
本文PS6的代码有一个错误…xyz()
产生错误:
非静态方法需要Object引用。
class Demo : abc
{
public static void Main()
{
System.Console.WriteLine("Hello Interfaces");
xyz();
}
public void xyz()
{
System.Console.WriteLine("In xyz");
}
}
interface abc
{
void xyz();
}
你能解释一下我的xyz()
调用是什么吗?它是方法、属性还是字段?我不知道它到底叫什么?
为什么这不起作用?当我们创建Demo的新实例时?
这…
Demo obj = new Demo();
obj.xyz();
public void xyz()
{
System.Console.WriteLine("In xyz");
}
- public表示它是一个公共方法,其他类可以进行交互用它。
- void表示返回void,也就是什么都没有
- xyz是名称方法
- ()是参数所在的位置,但是这里没有方法调用的参数,所以它是空的 括号之间的
- 是代码块,也称为函数体或方法体
Main方法被标记为代码执行开始的地方,所以你应该从那里开始。
你能解释一下我的
xyz()
调用是什么吗?是方法,属性,还是字段?
这是一个Method
。
为什么不工作?
因为xyz()
没有定义为static
,也不能定义为static
,因为修饰符static对接口成员声明无效。所以你应该创建这样的实例:
Demo obj = new Demo();
obj.xyz();
编辑:
使用接口不仅可以保证标准化、灵活性、可伸缩性、可扩展性、可维护性、可重用性、可测试性和功能,而且c#中使用接口的一个主要原因是c#不支持多(类)继承。我们为什么要使用这个接口呢?
xyz
是一个方法。确切地说,是一个实例方法,所以让我试着解释为什么你不能从静态方法Main调用它,以及如何解决这个问题。
类定义定义了哪些方法(和属性等)。如果你创建了一个实例(new Demo
),你就得到了一个对象。一个对象引用类,这样你就知道它包含什么功能,它有自己的数据块,你可以在其中存储值,所以10个实例可以包含10个不同的值。
例如:
class Demo {
public string name;
}
var a = new Demo();
a.name = 'John';
var b = new Demo();
b.name = 'Bob';
// At this point, a.name is still John. a and b each have their own name.
一个普通的方法是一个实例方法。它可以访问并使用这些实例变量。因此,扩展前面的示例,您可以这样做:
class Demo {
public string name;
public void WhoAmI() {
System.Console.WriteLine(this.name);
}
}
var a = new Demo();
a.name = 'John';
var b = new Demo();
b.name = 'Bob';
a.WhoAmI(); // outputs 'John'
现在,除了那些实例变量和实例方法之外,您还获得了静态成员(成员是变量、方法、属性…)。静态意味着它们不属于实例,而属于类定义。在应用程序中只有一个。它们属于类而不是实例。
现在,对象实例知道它属于哪个类。如果您创建了一个变量var a = new Demo()
,那么a
就知道它是Demo
,因此可以从它或通过它调用静态方法,例如示例中的Main
。
然而,在静态方法中,如果不知道它所属的实例。毕竟,甚至不需要实例。可以调用a.Main()
,也可以调用Demo.Main()
。因此,不能使用实例变量,也不能调用实例方法。因为xyz
是一个实例方法,所以不能从静态方法Main
调用它。
现在这个问题的解决方案可能是使xyz
静态。毕竟,它不引用其他实例成员。然而,接口不允许这样做,所以这会抛出另一个错误。接口描述实例的样子,不支持静态成员。这是c#中的一个设计决策。
因此,您也可以引入一个额外的静态实现,并从接口方法调用它。这样,接口实现仍然可以调用静态版本,就像Main方法一样:
class Demo : abc
{
public static void Main()
{
System.Console.WriteLine("Hello Interfaces");
zyx();
}
public static void zyx() {
System.Console.WriteLine("In zyx");
}
public void xyz()
{
zyx();
}
}
interface abc
{
void xyz();
}
关于接口。我看到你在评论里问这个问题。接口有很多用途,尽管它们的解释在这里有点超出了范围。但是请注意,并不是每个类都需要接口。因此,如果在您的特定实现中不需要接口,那么您也不需要我介绍的额外方法。CodeProject让您实现接口的原因是因为它是本教程的主题。;)
他们在教程的介绍中简要地总结了接口的优点:
c#中的接口提供了一种实现运行时多态性的方法。使用接口可以调用来自不同类的函数相同的接口引用,而使用虚函数则可以调用同一继承中的不同类的函数层次结构通过相同的引用
所以,如果你有不同种类的Demo类,你可以相互扩展它们:
class BaseDemo {
abstract void xyz() {
System.Console.WriteLine("in Basedemo.xyz");
}
}
class SpecificDemo1: BaseDemo {
override void xyz() {
System.Console.WriteLine("in SpecificDemo1.xyz");
}
}
class SpecificDemo2: BaseDemo {
override void xyz() {
System.Console.WriteLine("in SpecificDemo2.xyz");
}
}
现在,你可以这样声明一个方法:
class DemoUser {
static void CallXyz(BaseDemo d) {
d.xyz();
}
}
var a = new SpecificDemo2();
DemoUser.CallXyz(a);
CallXyz接受类型为SpecificDemo1和SpecificDemo2的变量。这样做的原因是它的参数被声明为BaseDemo类型,所以它接受BaseDemo的所有后代的实例。
然而,创建大的类层次结构来支持这一点是没有用的和不可维护的,所以这就是接口的由来。您可以捕获界面中的一小部分功能,然后使用它。
示例,在下面的代码中,我在接口中声明了两个函数:Foo和Bar。有三个类实现了这些接口中的一个或多个。类本身是不相关的。它们可以,但从界面的角度来看,这并不重要。
class Foo: IFoo {
public void DoFoo() {
System.Console.WriteLine('Foo is fooing');
}
}
class Bar: IBar {
public void DoBar() {
System.Console.WriteLine('Bar is barring');
}
}
class FooBar: IFoo, IBar {
public void DoFoo() {
System.Console.WriteLine('FooBar is fooing');
}
public void DoBar() {
System.Console.WriteLine('FooBar is barring');
}
}
IFoo {
void DoFoo() {
}
IBar {
void DoBar() {
}
现在,如果有一个方法想要'Bar'一些东西,它可以接受一个IBar参数。这样的方法接受Bar和Foobar的实例。
对于正常继承,这是无法实现的。你必须从Foo和Bar都继承FooBar,这是不可能的,或者你必须让FooBar成为基类,在这种情况下,你必须已经在基类中声明这两个方法。这也意味着Foo实例可以作为Bar传递,反之亦然。这是不可取的。
使用接口,您可以简单地声明一个小功能,并在任何您喜欢的类中实现它。