关于c#:当我输入对象时,我使用接口或类之间有什么区别?


When I type objects is there any difference between me using an Interface or a class?

我创建了这个界面:

1
2
3
4
5
6
7
8
9
public interface IPhrase
{
    int CategoryId { get; set; }
    string PhraseId { get; set; }
    string English { get; set; }
    string Romaji { get; set; }
    string Kana { get; set; }
    string Kanji { get; set; }
}

这门课:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Phrase : IPhrase
{
    public Phrase()
    {
    }

    public int CategoryId { get; set; }
    public string PhraseId { get; set; }
    public string English { get; set; }
    public string Romaji { get; set; }
    public string Kana { get; set; }
    public string Kanji { get; set; }
}

在此,此代码返回数据并将其类型转换为短语:

1
2
var phrases = db2.Query<Phrase>("SELECT * FROM Phrase", ans);
var phrases = db2.Query<IPhrase>("SELECT * FROM Phrase", ans);

我想知道的是,我在这里使用IPhrasePhrase是否有任何区别/优势?另外,在本例中,我创建一个IPhrase接口有什么好处(如果有的话)。这会导致代码更可读吗?


接口是一个保证的契约,任何实现接口的类都将实现接口中定义的方法和属性。这允许您使用接口创建方法、列表等,这些方法、列表等接受实现接口的任何类,例如

1
2
3
4
5
6
7
8
9
10
public interface IExample
{
    int GetInt();
}

public void ProcessInt(IExample value)
{
    var tempInt = value.GetInt();
    // Do processing here
}

这允许将实现接口iexample的任何具体类传递给此方法。该方法可以确保传递的任何具体类都将实现getint方法。


对于对象,可以从继承到:

  • 其他对象
  • 接口
  • 对象

    如果你有一个Animal物体,那么Dog物体可以继承自它,因为它是一种动物。

    有了对象继承,我们可以想到一个短语:I am a ...._yourObject_...

    接口

    通过一个接口,您可以把它看作是该对象的描述器。如IWalkOnTwoLegsICanSwim

    所以想想这个短语:I can do ...._yourInterface_..

    现在,为了回答您的问题,如果您使用接口或不使用接口,会有什么不同吗?

    嗯,在这种情况下不会,但是如果你扩展你的短语并创建一个Question对象和一个Statement对象,例如,它们继承自Phrase,你可以选择返回所有短语(问题和陈述),或者只返回Questions或只返回Statements的短语。

    您还可以在短语中应用一个名为IAmInFrenchIAmInSpanish的接口,这样您就可以扩展SpanishPhraseFrenchPhrase对象。现在,您可以返回所有短语,不管它们是问题、陈述,还是使用不同的语言,或者您可以是特定的,只返回法语阶段。

    我发现接口最有用的地方是在统一中注册不同类型。

    其中会产生影响:

    如果对象上有一个不在接口上的属性,那么如果您返回接口,那么除非您键入cast,否则您将无法很容易地访问该属性。

    如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class Phrase : IPhrase
    {
        public Phrase()
        {
        }

        public int CategoryId { get; set; }
        public string PhraseId { get; set; }
        public string English { get; set; }
    }

    和接口

    1
    2
    3
    4
    public interface IPhrase
        {
          int CategoryId { get; set; }
        }

    如果返回接口,将无法访问属性English:

    1
    2
    var phrases = db2.Query<IPhrase>("SELECT * FROM Phrase", ans);
    var eng = phrases[0].English; //**THIS WONT WORK**


    在本地使用接口和具体对象之间没有区别,如您的示例中所示。主要的区别在于,当您在API或构造函数参数中发送接口与具体类作为参数时,其中最好使用接口,以便实现解耦和可测试性。

    尽管如此,对于您的问题,简短的回答是"否",没有区别,您是否希望使用接口或具体对象作为局部变量是您自己的选择(您似乎更容易阅读)。不要忘记字段和属性很好地声明为接口,这样可以提供更大的灵活性。

    当使用一个具体的对象而不是一个接口(甚至在本地)时,最后一件应该考虑的事情是,你可能希望有一天改变方法的签名,这个方法提供给你这个对象返回另一种实现相同接口的对象,在这种情况下,你也应该改变本地变量(即使它是n哦,太糟糕了,而且很少发生,我不得不注意它),如下面的例子所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    interface IAnimal
    {
        void Run();
    }

    class Cat : IAnimal
    {
        public void Run()
        {
            //...
        }
    }

    class Dog : IAnimal
    {
        public void Run()
        {
            //...
        }
    }

    如果您的代码中有一个方法返回您使用的Cat

    1
    2
    3
    4
    5
    6
    7
    Cat GetAnimal()
    {
        return new Cat();
    }

    Cat myAnimal = GetAnimal(); //note that here it is expected a Cat
    myAnimal.Run();

    然后,如果更改GetAnimal签名以返回Dog,则应更改代码以编译为:

    1
    2
    Dog myAnimal = GetAnimal(); //note that here it is expected a Cat
    myAnimal.Run();

    但是,如果您使用的是接口,那么当方法的签名ar发生更改时,您的代码就不太可能需要更改:

    1
    2
    IAnimal myAnimal = GetAnimal(); //this is working whether a Cat or a Dog is received.
    myAnimal.Run();

    但这种情况再次发生的可能性相对较小。为愚蠢的猫和狗的例子道歉!


    你的答案取决于你想如何使用你未来的课程。接口是契约,以确保子类具有接口的所有定义。所以当您想要使用多态性时,这是很有用的。通过这种方式,您可以在接口类中定义对象的所有公共规范。接口的另一个优点是您的类可以从多个接口继承,这对于C中的其他类型的类是不允许的。下面是一个示例代码。希望对你有用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    public interface IShape
    {
        float Area { get; }
        float circumference { get; }
    }
    public class Rectangle : IShape
    {
        private float l, h;
        public Rectangle( float length, float height ) { l = length; h = height; }
        public float Area { get { return l * h; } }
        public float circumference { get { return ( l + h ) * 2; } }
    }
    public class Circle : IShape
    {
        private float r;
        public Circle( float radius ) { r = radius; }
        public float Area { get { return (float)Math.PI * r * r; } }
        public float circumference { get { return (float)Math.PI * r * 2; } }
    }

    public class SomeClass
    {
        IShape[] shapes = new IShape[] // Can store all shapes regardless of its type
        {
            new Rectangle( 10f, 20f ),
            new Rectangle( 15f, 20f ),
            new Rectangle( 11.6f, .8f ),

            new Circle( 11f ),
            new Circle( 4.7f )
        };
        public void PrintAreas()
        {
            foreach ( var sh in shapes )
                Console.WriteLine( sh.Area ); // prints area of shape regardless of its type
        }

        public void PrintCircumference(IShape shape )
        {
            Console.WriteLine( shape.circumference ); // again its not important what is your shape, you cant use this function to print its cicumference
        }
    }

    类是对象的模板。它本质上是一个蓝图。所以对于灯来说,有一个开关按钮。比如当你调用这个方法时,一个值被发送到某个控制器,这个控制器会打开和关闭它。你所要做的就是调用开/关的方法,然后Viola就可以了。

    接口非常相似。这里可能没有实现开/关方法。实际上,您必须编写代码来打开和关闭灯,但您必须编写打开/关闭方法,否则它不能是该接口。假设有一种新型的灯光具有调光功能。界面允许您为不同类型的光实现这个新功能。所以它基本上告诉你,你必须做这些事情(开/关),它是一个灯,但我们不关心你如何实现它。接口的某些部分可以为您实现,但其他部分必须实现。

    什么时候接口才有意义?一种情况,其中有许多对象在性质上非常相似,但在实现上略有不同。例如,假设您有许多类型的形状。每个都有一个区域。三角形的计算与圆形的计算不同。现在假设您有数百个需要构建的形状,您不会一直为每种类型的形状创建新的对象,您只需要实现接口。这使某人有能力用相似的方法创建形状,甚至自定义形状,但实现方式不同。