interface i1
{
void add();
}
class abc : i1
{
public void add()
{
Console.WriteLine("hi! add");
}开发者_如何学Go
}
now in Main
I create two objects, like:
abc obj1 = new abc();
and
i1 obj2 = new abc();
Please tell me, what is the difference between the above two instantiations?
The difference is that obj1
is typed as an instance of abc
and obj2
is typed as an instance of i1
. Both of these variables are references to instances of abc
, but the difference comes in what is accessible in code. Let's say you have the following:
interface IFoo { void Bar(); }
public class Foo : IFoo {
public void Bar() { Console.WriteLine("Foo.Bar!"); }
public void Baz() { Console.WriteLine("Baz!"); }
}
Then:
Foo foo = new Foo();
IFoo iFoo = new Foo();
Then the following is legal:
foo.Baz();
but this is not:
iFoo.Baz(); // compile-time error
The point is that the compiler doesn't know that the referrent of iFoo
is actually a Foo
and thus has a method Baz
. In particular, note that this is possible:
public class FooFoo : IFoo {
public void Bar() { Console.WriteLine("FooFoo.Bar!"); }
}
IFoo foofoo = new FooFoo();
foofoo.Baz(); // not legal
Note that it's not legal to do this, and it's clear why. The only methods that you can invoke through a variable of type IFoo
are those defined in the interface, regardless of any methods that might exist on the concrete type referred to by the variable of type IFoo
.
In the code you've shown, since there are no explicit implementations and no members besides the i1
implementation, there are no practical differences. Additionally, you specially ask about differences in the instantiation - since you're calling the same constructor in both cases, there is no difference. However, with different code, there could be some significant differences.
In the first example:
abc obj1 = new abc();
You will have access to the following:
- Public members of
abc
- Protected members of
abc
if called from within a derived class ofabc
- Internal members of
abc
, if called from within the same assembly - Private members of
abc
, if called from elsewhere within theabc
class itself
You will not have access to any explicitly implemented interface members.
In the second example:
i1 obj2 = new abc();
You will only have access to the members defined on the interface i1
An interface defines a contract between a caller and a callee. Any object which implements that interface also implements the contract. So you could also have
class cde : i1 { public void add() { console.writeline("cde add!"); } }
and then have a function:
void myFunction(i1 adder) { adder.add(); }
which is called as follows:
i1 myAbc = new abc();
i1 myCde = new cde();
myFunction(myAbc);
myFunction(myCde);
Even though two classes implement i1, they both implement the same contract and thus myFunction can call into methods on either.
In the case you've shown, there's no difference for most practical purposes.
However, let's say abc
implemented other interfaces besides i1
:
interface i1 { void add(); }
interface i2 { void subtract(); }
class abc : i1, i2
{
public void add() { ... }
public void subtract() { ... }
}
Now, if you repeat your instantiations:
abc obj = new abc();
i1 obj1 = new abc();
i2 obj2 = new abc();
You end up with three references to three abc
s, but these references allow you to do different things:
- You can call both
add
andsubtract
onobj
; - You can call
add
onobj1
; - You can call
subtract
onobj2
;
That is because an interface type only gives you a "partial view" on a concrete type. (While this sounds like a constraint, it is actually a good thing, because it allows you to explicitly state, e.g. in a method's parameter list, what kind of behaviour, or contract, you expect from that parameter; it documents what you're requiring or plan to do with that parameter.)
The interface-related difference is that if abc implements anything other than i1 (some other interface or just other methods or public members) you'll be able to access them for obj1, but not on obj2.
The biggest difference is that obj1 would only be able to hold objects of type "abc" or a type derived therefrom, whereas obj2 would would be able to hold any object that implements "i1". The next-biggest difference is that obj1 could be passed to methods that expects an "abc" or an "i1", while the obj2 could only be passed to methods that expect an "i1".
Note that while both obj1 and obj2 will initially hold objects of type "abc", but that does not imply that they will never at some later time hold other objects, which could be of other types. Because obj2 would be allowed to hold objects of types other than "abc", whether or not it actually ever does, the compiler won't allow it to be passed to methods that require an "abc".
精彩评论