Does this IConvertible
interface satisfy the Interface Segregation Principle (ie. the "I" in SOLID)?
Here is the definition:
public interface IConvertible
{
TypeCode GetTypeCode();
bool ToBoolean(IFormatProvider provider);
byte ToByte(IFormatProvider provider);
char ToChar(IFormatProvider provider);
DateTime ToDateTime(IFormatProvider provider);
decimal ToDecimal(IFormatProvider provider);
short ToInt16(IFormatProvider provider);
int ToInt32(IFormatProvider provider);
long ToInt64(IFormatProvider provider);
sbyte ToSByte(IFormatProvider provider);
float ToSingle(IFormatProvider provider);
string ToString(IFormatProvider provider);
object ToType(Type conversionType, IFormatProvider provider);
ushort ToUInt16(IFormatProvider provider);
uint ToUInt32(IFormatProvider provider);
ulong ToUInt64(IFormatProvider provider);
}
So if I would like to have a class which will implements this IConvertible
interface the I have to implement all of those methods, right? Or if I don't implement all of them, then I have to at least make an empty method or throw an Exception, right?.
In my opinion, the better way is to make more interface with fewer methods, for example:
public interface IConvertibleInt
{
short ToInt16(IFormatProvider provider);
int ToInt32(IFormatProvider provider);
long ToInt64(IFormatProvider provider);
}
Or even:
public interface IConvertibleInt16
{
short ToInt16(IFormatProvider provider);
}
public interface IConvertibleInt32
{
int ToInt32(IFormatProvider provider);
}
public interface IConvertibleInt64
{
long ToInt64(IFormatProvider provider);
}
Is my reasoning correct?
3 Answers 3
I like to interpret Interface Segregation Principle as
Interface should be closer related to the code that uses it than code that implement it. So the methods on the interface are defined by which methods client code needs than which methods class implements.
This implies that for each interface, there is always code that uses this interface. This is not the case of IConvertible
. The interface itself doesn't make much sense. I also never saw property or function that was typed IConvertible
, which empowers my claims. I even wonder how would code that only works on IConvertible
looks and what would it do.
One difficulty with applying the Interface Segregation Principle in .NET is that any given storage location must have a single specified type. If there had been separate interfaces for IConvertibleToInt32
, IConvertibleToInt64
, then a type which only supported some of the conversions would only have to implement the ones it supported; code which needed exactly one conversion interface could accept a parameter of that type. Unfortunately, splitting things up in that fashion would make it difficult to write code which needs more than one conversion interface. For example, if a method needed to use IConvertibleToInt32
, but which needed to pass an object to a method that needed IConvertibleToInt64
, there would be no way to specify that it needed an object which supported both interfaces unless there were existed an interface which inherited from both and all types of interest which implement both interfaces also implement the composite one.
If .NET made had a means of defining a special kind of "composite" interface such that any class which implemented all of the components would automatically be regarded as an implementation of the composite, then it would make sense to subdivide interfaces much more finely. The lack of such ability, however, makes it necessary to define interfaces which are much coarser than would be ideal.
-
1
If .NET made had a means of defining a special kind of "composite" interface such that any class which implemented all of the components would automatically be regarded as an implementation of the composite
- or duck typing, isn't it. Actually I believe generics could be put to a good use here, I'm thinking along the lines ofIConvertible<F, T>
(where F stands for from and T - the target type). Generics allow for type constraints, so perhaps this could be more flexible.Konrad Morawski– Konrad Morawski03/26/2014 09:28:35Commented Mar 26, 2014 at 9:28 -
@KonradMorawski: The best pattern I've found is
interface ISelf<out T> { T self {get;} }
. If all of the interfaces of interest include an extra parameterTExtra
and inheritISelf<TExtra>
, one can sort of achieve composite interfaces, provided that every implementation ofISelf<anything>
implementsISelf<itsOwnType>
. One doesn't avoid typecasting, however, and if a reference is cast and assigned to variablex
of typeIFoo<IBar<IBoz>>>
, thenx
will implementIFoo
,x.self
will implementIBar
, andx.self.self
will implementIBoz
. For a class implementing the pattern...supercat– supercat03/26/2014 15:13:19Commented Mar 26, 2014 at 15:13 -
...all three references will identify the same object, and one could cast
x
toIBar<IFoo>
or any other desired permutation, but nothing would prevent someone from implementing a class where such behaviors wouldn't hold. What I'm asking for would be a bit like duck-typing, but a bit more formal and structured than typical duck-typing languages (since types that implementIFoo
andIBar
could only satisfy code that simply wants the combination, rather than code which demands a particular composite interface).supercat– supercat03/26/2014 15:16:26Commented Mar 26, 2014 at 15:16 -
@Konrad IConvertible<F, T> does not seem useful to me because "from" is implied by the type that implements the interface. IConvertible<T> could work but still sort of defeats the purpose of an interface: there is no common behavior defined, it basically defines an unlimited number of behaviors. But there may be corner cases for which it is useful, the bottom line is that IConvertable was introduced with .NET 1.1 which did not support generics yet. And apparently they did not see added value in an additional IConvertable<T> like they did with IEnumerable<T> and others.Martin Maat– Martin Maat01/04/2019 16:50:55Commented Jan 4, 2019 at 16:50
IConvertible
neither violates nor conforms to the Interface Segregation Principle. The principle is followed or not by classes that depend on the interface, not by the interface.
One class could depend on the interface and use every method, not violating the principle. Another could depend on the interface and use one method, violating the principle. Does this mean that IConvertible
both violates and does not violate the principle? No. It means that one class depending on it does and the other does not.
Yes, IConvertible
is a weird interface, but in isolation it doesn't illustrate the ISP.
It's also worth considering the reason behind the principle, which is that if multiple classes depend on different methods of an interface, one "client" might exert backwards pressure to change the interface, which means modifying an interface and possibly implementations which could affect unrelated code. It's a form of coupling.
It's very unlikely that IConvertible
will change to meet the needs of any individual clients, so the risk which is the reason for the principle is mitigated.
Explore related questions
See similar questions with these tags.
IConvertible
violate Interface Segregation Principle?