I'm currently facing a problem in C# that I think could be solved using existential types. However, I don't really know if they can be created in C#, or simulated (using some other construct).
Basically I want to have some code like this:
public interface MyInterface<T>
{
T GetSomething();
void DoSomething(T something);
}
public class MyIntClass : MyInterface<int>
{
int GetSomething()
{
return 42;
}
void DoSomething(int something)
{
Console.Write(something);
}
}
public class MyStringClass : MyInterface<string>
{
string GetSomething()
{
return "Something";
}
void DoSomething(string something)
{
SomeStaticClass.DoSomethingWithString(something);
}
}
Next I want to be able to iterate through a list of objects that implement this interface, but without caring what type parameter it has. Something like this:
public static void DoALotOfThingsTwice(){
var listOfThings = new List<MyInterface<T>>(){
new MyIntClass(),
new MyStringClass();
};
foreach (MyInterface<T> thingDoer in listOfThings){
T something = thingDoer.GetSomething();
thingDoer.DoSomething(something);
thingDoer.DoSomething(something);
}
}
This doesn't compile because the T
used by MyIntClass
and the one used by MyStringClass
are different.
I was thinking that something like this could do the trick, but I don't know if there's a valid way to do so in C#:
public static void DoALotOfThingsTwice(){
var listOfThings = new List<∃T.MyInterface<T>>(){
new MyIntClass(),
new MyStringClass();
};
foreach (∃T.MyInterface<T> thingDoer in listOfThings){
T something = thingDoer.GetSomething();
thingDoer.DoSomething(something);
thingDoer.DoSomething(something);
}
}
Existential types, or 'existentials' for short, are a way of 'squashing' a group of types into one, single type. Existentials are part of GHC's type system extensions.
Existentials in Swift allow defining a dynamic value conforming to a specific protocol. Using primary associated types, we can constrain existentials to certain boundaries. The Swift team introduced the any keyword to let developers explicitly opt-in to a performance impact that might otherwise not be visible.
Since DoALotOfThingsTwice
doesn't depend on T
you can wrap it in an Action
and store those in the list instead e.g.
public static Action DoSomethingTwice<T>(this MyInterface<T> i)
{
return () =>
{
T something = i.GetSomething();
i.DoSomething(something);
i.DoSomething(something);
};
}
then
var listOfThings = new List<Action>() {
new MyIntClass().DoSomethingTwice(),
new MyStringClass().DoSomethingTwice()
};
Not possible directly in C#.
You can either drop type safety and have non-generic base interface and use it for "generic" code:
public interface MyInterface
{
object GetSomething();
void DoSomething(object something);
}
public interface MyInterface<T> : MyInterface
{
T GetSomething();
void DoSomething(T something);
}
Or use dynamic
(again no compile time type safety):
foreach (dynamic thingDoer in listOfThings)
{
dynamic something = thingDoer.GetSomething();
thingDoer.DoSomething(something);
thingDoer.DoSomething(something);
}
Or generate multiple versions of the handler and create (possibly with caching) based on type (How do I use reflection to call a generic method?) (Note: that you can't really express "list of arbitrary objects" better than List<object>
or List<NonGenericBaseInterface>
or List<NonGenericBaseClass>
):
foreach (object thingDoer in listOfThings)
{
// get Do via reflection and create specific version based on
// thingDoer.GetType(), than invoke
// consider caching "methodForType" in Dictionary by type
MethodInfo method = this.GetType().GetMethod("Do");
MethodInfo methodForType = method.MakeGenericMethod(thingDoer.GetType());
methodForType.Invoke(thingDoer, null);
}
void Do<T>( MyInterface<T> thingDoer)
{
T something = thingDoer.GetSomething();
thingDoer.DoSomething(something);
thingDoer.DoSomething(something);
}
Alternative to reflection is to use Expression tree to build similar code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With