如何从其父接口获取派生类的实际类型

Tar*_*rik 33 .net c# interface class

假设我们有一个像这样的代码部分:

IProduct product = ProductCreator.CreateProduct(); //Factory method we have here
SellThisProduct(product);

//...

private void SellThisProduct(IProduct product)
{
  //.. Do something here
}

//...

internal class Soda : IProduct
{}

internal class Book : IProduct
{}
Run Code Online (Sandbox Code Playgroud)

如何推断哪个产品实际传递到方法中的SellThisProduct()方法?

我想如果我说GetType()或者它可能会返回IProduct类型.

Joh*_*lla 56

GetType获取对象的确切运行时类型.从文档:

Type实例,表示当前实例的确切运行时类型.

您还可以使用它is来确定对象是否是特定类型的实例:

var noise = (obj is Velociraptor) ? "SKREEE!" : "<unknown>";
Run Code Online (Sandbox Code Playgroud)

但是,为什么需要确切的运行时类型?接口的全部内容是您应该隐藏公共接口背后的实现细节.如果你需要根据类型采取行动,这是一个很大的暗示,你违反了它提供的封装.

一种替代方法是使用多态:

public interface IVocalizer { string Talk(); }

public class Doorbell : IVocalizer {
  public string Talk() { return "Ding-dong!" }
}
public class Pokemon : IVocalizer {
  public string Talk() {
    var name = this.GetType().ToString();
    return (name + ", " + name + "!").ToUpper(); } // e.g., "PIKACHU, PIKACHU!"
}
public class Human : IVocalizer {
  public string Talk() { return "Hello!"; }
}
Run Code Online (Sandbox Code Playgroud)

由于这三种类型根本不相关,因此从常见类型继承是没有意义的.但是为了表示它们具有相同的制造噪声的能力,我们可以使用IVocalizer接口,然后让每个人发出噪音.这是一种更清洁的方法:现在,当您想要让它产生噪音时,您无需关心对象的类型:

IVocalizer talker = new ???();  // Anything that's an IVocalizer can go here.

// elsewhere:
Console.WriteLine(talker.Talk());    // <-- Now it doesn't matter what the actual type is!
                                     //   This will work with any IVocalizer and you don't
                                     //   need to know the details.
Run Code Online (Sandbox Code Playgroud)

  • 顺便说一下你说的口袋妖怪:D (2认同)
  • 我刚刚意识到我在我的应用程序中提交了多少糟糕的多态性.不好的程序员!我得到了很多案例声明重新进入jig. (2认同)

Aar*_*ght 10

Object.GetType返回实例的确切运行时类型.这就是你应该使用的.

虽然,一般来说,你根本不应该关心接口的运行时类型 - 如果你正在编写代码来确定它,它可能反映了你的设计中的某个错误.

实际上,接口名称IProduct已经有点代码味道了.这本身并没有错,但接口意味着定义特定对象可用的操作,即它的作用.这个名字IProduct似乎是描述什么,不在于它,这是更适合的抽象基类.请注意,这不是一个"规则",但它是一个很好的指导方针.

在编写依赖于抽象类型(基类或接口)的方法/类时,如果发现依赖于更多派生类型或特定实现,则意味着您的抽象类型是贫血的(没有足够的功能)要有效地使用),或者你的依赖关系有太多耦合(取决于实现细节而不是抽象).

考虑扩展Product/ IProduct做更多,或通过方法重载使您的依赖实际上对特定产品类型起作用.