I need to create two partial interfaces. One with a constraint and the other without, like:
public partial interface IMyCuteInterface<T> where T : IEnumerable
{
void DoSomethingOnlyPossibleIfGenericIsIEnumerable();
}
public partial interface IMyCuteInterface<T>
{
void DoSomeStuff();
void DoSomeStuff2();
}
This is the implementation:
public class CuteInterfaceImplementation<T> : IMyCuteInterface<T>
{
private readonly T _element;
public CuteInterfaceImplementation(T element)
{
_element = element;
}
public void DoSomethingOnlyPossibleIfGenericIsIEnumerable(){}
public void DoSomeStuff(){}
public void DoSomeStuff2() { }
}
This is a static method to get this more dynamically:
public class CuteInterfaceImplementationBase
{
public static IMyCuteInterface<T> From<T>(T t)
{
return new CuteInterfaceImplementation<T>(t);
}
}
and this is the way I want to call it:
public static void Main(string[] args)
{
var mci = CuteInterfaceImplementationBase.From(args);
}
So, C# wants me to add the generic type constraint I added in the first interface to my CuteInterfaceImplementationBase.From<T>
and my CuteInterfaceImplementation<T>
-class.
What I want to achieve is: args
could either be e.g. from type List<T>
or from type int
or something else. My target is, if args
is from type IEnumerable<T>
I want to add more functions (via the interface with the constraint) to CuteInterfaceImplementation
-instance.
example:
if args is from type IEnumerable
, this instance from CuteInterfaceImplementation
has methods:
void DoSomethingOnlyPossibleIfGenericIsIEnumerable();
void DoSomeStuff();
void DoSomeStuff2();
if args is from type Foo
or int
(or any type that doesn't implement IEnumerable
) I can use methods:
void DoSomeStuff();
void DoSomeStuff2();
means, DoSomethingOnlyPossibleIfGenericIsIEnumerable
is not available.
But it seems, this is not possible, since I need to add the constraint to my implemented class. Any idea how to do this?
Not sure that this approach good idea, it violates the "I" in SOLID - interface segregation
no client should be forced to depend on methods it does not use
You're using partial
to split up two fundamentally different interfaces, you should have 2 different interface because they are different.
To answer your question:
If you're committed to a similar approach on the conditions of T
, you could split the interfaces, move the "common logic" (which both interfaces use) to a base class and use the From<T>
method to conditionally choose which implementation to create.
Something like this:
public partial interface IMyCuteInterface_WITHEnumerable<T> : IMyCuteInterface<T> where T : IEnumerable
{
void DoSomethingOnlyPossibleIfGenericIsIEnumerable();
}
public partial interface IMyCuteInterface<T>
{
void DoSomeStuff();
void DoSomeStuff2();
}
And then the implementations:
public class CuteInterfaceImplementation<T> : CuteInterfaceImplementation_COMMON<T>
{
public CuteInterfaceImplementation(T element) : base(element)
{
}
}
public class CuteInterfaceImplementation_COMMON<T> : IMyCuteInterface<T>
{
private readonly T _element;
public CuteInterfaceImplementation_COMMON(T element)
{
_element = element;
}
public void DoSomeStuff() { }
public void DoSomeStuff2() { }
}
public class CuteInterfaceImplementation_WITHEnumerable<T> : CuteInterfaceImplementation_COMMON<T>, IMyCuteInterface_WITHEnumerable<T> where T : IEnumerable
{
private readonly T _element;
public CuteInterfaceImplementation_WITHEnumerable(T element) : base(element)
{
_element = element;
}
public void DoSomethingOnlyPossibleIfGenericIsIEnumerable() { }
}
Finally your "static helper", which decides on the class to instantiate:
Unfortunately it's not possible in C# to conditionally instantiate the different classes because one expects T
to be IEnumerable
while the other doesn't. You can get around that using dynamic
public class CuteInterfaceImplementation_HELPER
{
public static IMyCuteInterface<T> From<T>(T t)
{
if (t is IEnumerable)
{
dynamic dyn = t;
return FromEnumerable(dyn);
}
else
{
return new CuteInterfaceImplementation<T>(t);
}
}
public static IMyCuteInterface<T> FromEnumerable<T>(T t) where T: IEnumerable
{
return new CuteInterfaceImplementation_WITHEnumerable<T>(t);
}
}