如何从具体类转换为接口类型?

Ken*_*nci 3 c#

我正在构建一个多层应用程序.

当我将一个对象从我的表示层传递到我的业务层时,我想将它转换为接口类型,因为业务层不知道表示层中的具体类.

    public ActionResult SubmitSurvey(SurveyAnswer answers)
    {

        ISurveyAnswer answer = (ISurveyAnswer)answers;

        bc.SaveSurvey(answer);

        return null;
    }
Run Code Online (Sandbox Code Playgroud)

该类SurveyAnswer实现了ISurveyAnswer接口

当我检查业务层中的类型时:

 public void SaveSurvey(ISurveyAnswer answer)
        {
            String type = answer.GetType().Name;
        }
Run Code Online (Sandbox Code Playgroud)

GetType().Name方法返回SurveyAnswer,它是表示层中的具体类.它应该这样做吗?

Ste*_*art 9

转换不会更改对象的类型.对象始终与创建时保持一致.强制转换只会更改您访问对象的界面.如果愿意,它会改变对象的"视图".不过,这不是问题.你在做什么是正确的.所有UI层关心的都是ISurveyAnswer接口,因此只要对象的具体类型实现了该接口,那么一切都很好并且将按预期工作.这样做的美妙之处在于,现在UI层可以被赋予任何类型的对象(包括模拟对象)并且无关紧要,只要对象实现相同的界面,UI将起作用并且不关心.GetType将允许您检查对象以查看对象的实际类型,但在大多数情况下,它对UI层无关紧要.只要提供的对象实现了该接口并且正常工作,UI也将如此.

当任何类或方法要求将某种类型的对象传递给它时,理想情况下应始终要求尽可能最窄的实现或基类型.例如,如果你有一个获取项目列表的方法,它可能看起来像这样:

void printList(List<Dog> dogs)
{
    foreach(Dog dog in dogs)
        printDog(dog);
}
Run Code Online (Sandbox Code Playgroud)

但是,从技术上讲,该方法并不真正需要一个List<>对象,因为它所做的只是枚举列表中的项目.它没有使用该List<>类型的任何成员本身,它只是使用IEnumerable<>接口的成员,这是由List<>类型实现的.因此,在这种情况下,将这样的方法编码更好:

void printList(IEnumerable<Dog> dogs)
{
    foreach(Dog dog in dogs)
        printDog(dog);
}
Run Code Online (Sandbox Code Playgroud)

现在,如果在方法内部,它不仅需要通过列表进行枚举,还需要列表中项目的总数,那么IEnumerable还不够.但是,它仍然不需要完整List<>类型,它只需要ICollection<>类型(也由实现List<>),如下所示:

void printList(ICollection<Dog> dogs)
{
    printTotal(dogs.Count);
    foreach(Dog dog in dogs)
        printDog(dog);
}
Run Code Online (Sandbox Code Playgroud)

但是如果方法需要获取每个项目的索引,ICollection<>这还不够 - 该方法需要一个IList<>类型.例如,此示例显示了如何打印狗列表并突出显示列表中的所有其他狗:

void printList(IList<Dog> dogs)
{
    printTotal(dogs.Count);
    for(Dog dog in dogs)
        if (dogs.IndexOf(dog) % 2 == 0)
            printDog(dog);
        else
            printHighlightedDog(dog);
}
Run Code Online (Sandbox Code Playgroud)

您会注意到,在这些示例中,我都不必将dogs参数转换为其他类型.我根据需要适当地输入了参数,所以我只是通过该类型的界面使用它.在所有这些示例中,List<Dog>可以在printList不进行转换的情况下将对象传递给方法(因为List <>实现了所有这些接口,因此可以隐式转换):

List<Dog> dogs = new List<Dog>();
dogs.Add(new Dog());
printList(dogs);
Run Code Online (Sandbox Code Playgroud)

请记住,这是一个非常简单的例子来说明一点.在现实世界的场景中,由于各种原因,您经常可能只是要求,List<>或者IList<>即使您在技术上并不需要他们提供的所有内容.您可能知道该方法很可能IList<>在将来需要功能,即使它IEnumerable<>今天只需要功能.但是,当您决定方法的参数类型时,要记住这个原则是非常好的原则.

您几乎不需要知道传递给方法的对象的实际类型.您真正需要知道的是它实现了一个特定的接口,以便您可以通过该特定接口访问其功能.


Ode*_*ded 5

我想将其转换为接口类型

无需。如果具体类型实现该类型,则无需强制转换。

这将正常工作:

public ActionResult SubmitSurvey(SurveyAnswer answers)
{
    bc.SaveSurvey(answers);
    return null;
}
Run Code Online (Sandbox Code Playgroud)

GetType()。Name方法将返回SurveyAnswer,这是表示层中的具体类。应该这样做吗?

没错 它将返回传入的实际类型(无论您将其强制转换为什么类型)。