if using an interface should a class always strictly implement an interface
The better way to ask this question would be an example as follows What are the pros and cons of the 2 approaches? Is one always better than the other or under specific circumstances? If using Approach1, using an interface would be moot right? since anyone can access the public methods anyway?
public interface IDoSomething
{
void Method1(string operation, User user, string category)
void Method2(string operation, User user)
void Method3(string operation)
}
//Approach1
Class A: IDoSomething
{
public void Method1(string operation, User user, string category)
{
//do some db logic here...
}
public void Method2(string operation, User user)
{
Method1(operation, user, "General");
}
public void Method3(string operation)
{
Method1(operation, User.GetDefaultUser(), "General");
}
}
OR
//Approach2
Class A: IDoSomething
{
void IDoSomething.Method1(string operation, User use开发者_如何学Cr, string category)
{
//do some logic here...
}
void IDoSomething.Method2(string operation, User user)
{
(this as IDoSomething).Method1(operation, user, "General");
}
void IDoSomething.Method3(string operation)
{
(this as IDoSomething).Method1(operation, User.GetDefaultUser(), "General");
}
}
The phrase you're looking for to describe the second approach is explicit interface implementation. Personally, I wouldn't use it most of the time. It's useful it you need to implement different interfaces with the same member signature in different ways, or if you want to restrict some members to only be visible when dealing with an expression of the interface type... but it can be a pain if for whatever reason your caller has the concrete type, and needs to call some type-specific methods and some interface methods. You can't even see explicitly implemented methods within the same class without casting this
to the interface type.
Explicit interface implementation also means that you can't override the interface methods - you'd have to reimplement the interface within any subclasses. Basically it ends up being quite complicated - so I'd avoid it if possible.
One final note: explicit interface implementation also plays badly with dynamic
in C# 4.
Approach 1 is the natural way of implementing interfaces in C#. If you write a library, this is what your customers will expect; if you use the class yourself, you save yourself a lot of casting when calling the methods.
Use Approach 2 (explicit interface implementation) if you have a good reason for doing so. Good reasons could include
- implementing multiple interface sharing the same method signature (but requiring different implementations),
- method names that make sense for the interface but could be misleading for your class.
It is (to some extent) a matter of taste. The main difference is that if you make an explicit implementation, those methods can't be invoked unless you first cast the object to the interface type:
A item = new A();
item.Method2(operation, user); // will not compile
(item As IDoSomething).Method2(operation, user); // works well
This approach is useful if you don't want the interface implementations to "clutter" the list of members in IntelliSense for some reason.
Personally I tend to use the implicit approach, unless there are specific reasons to "hide" the interface implementation.
One very common combination of the two is when implementing IEnumerable<T>
. Since IEnumerable<T>
inherits from IEnumerable
, then you must implement both IEnumerable<T>.GetEnumerator()
and IEnumerable.GetEnumerator()
. Since these have a different return type, but matching parameter list (empty), only one at most can be implicitly implemented.
The most common pattern is to implement the generic version:
public IEnumerator<T> GetEnumerator()
{
//some code that returns an appropriate object.
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();//return the result of the other call.
}
Now, one need not have either implicit, or one could (with a bit of casting in the explicit implementation) have this the other way around. However, this is handier for the following reasons:
- We probably would prefer that the implicit version is called, as its likely to have better type-safety and perhaps better efficiency if the enumerator object is dealt with through its more explicit interface.
- The implicit version will serve both calling code that wants an
IEnumerator<T>
and calling code that wants anIEnumerator
(as that's an implicit cast), and is hence the most useful.
Now, that case is one were we are forced to use an explicit interface. For an example of a case were we might choose to, consider writing a read-only list that wraps a List<T>
and implements IList<T>
.
All we have to do here is to delegate the reading operations to the wrapped list, and throw not supported for writing operations, e.g.:
public T this[int idx]
{
get
{
return _inner[idx];
}
set
{
throw new NotSupportedException("Read only list.");
}
}
public int Count
{
get
{
return _inner.Count;
}
}
public void Add(T item)
{
throw new NotSupportedException("Read only list.");
}
public bool IsReadOnly
{
get
{
return false;
}
}
And so on. However, this isn't very useful for people using the object by the concrete type, we've a whole bunch of members that either return the same result (IsReadOnly
) or always throw an exception. While code using the class through its interface has to be able to call these methods and properties, there's no value in doing so on the concrete class. Hence we can do as follows:
public T this[int idx]
{
get
{
return _inner[idx];
}
}
T IList<T>.this[int index]
{
get { return this[index]; }
set { throw new NotSupportedException("Collection is read-only."); }
}
public int Count
{
get
{
return _inner.Count;
}
}
void ICollection<T>.Add(T item)
{
throw new NotSupportedException("Read only list.");
}
bool ICollection<T>.IsReadOnly
{
get
{
return false;
}
}
Now while we fully implement IList<T>
we also offer a much cleaner and more useful interface (in the general rather than c# specific sense of "interface") to users of the concrete class.
Note that this builds precisely on the reason it normally makes more sense to be implicit: We've made all of these members more awkward for a user of the concrete class to get to (such code would have to cast to IList<T>
first). This is good here, as the only result of such awkward code is pointless or dangerous, and making bad ideas harder to do is a good thing. If such awkwardness was just getting in the way, it would be a different matter.
精彩评论