13
votes

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);
    }
}
4
As the type is invariant, no, that's not possible.Servy
You could wrap the operation in an Action and then store those in a list. You can create those actions generically.Lee

4 Answers

5
votes

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()
};
5
votes

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.

5
votes

This is actually possible in a completely type-safe way and without any type casts and without any assumptions about what the interface functions do.

https://dotnetfiddle.net/buneul

using System;
using System.Collections;
using System.Collections.Generic;

public interface MyInterfaceFunc {
    void Call<T>(MyInterface<T> obj);
}

public interface MyInterface {
    void Generically(MyInterfaceFunc func);  // this is the key!
}

public interface MyInterface<T> : MyInterface
{
    T GetSomething();
    void DoSomething(T something);
}

public class MyIntClass : MyInterface<int>
{
    public int GetSomething()
    {
        return 42;
    }

    public void DoSomething(int something)
    {
        Console.Write(something);
    }

    public void Generically(MyInterfaceFunc func) {
        func.Call(this);
    }
}

public class MyStringClass : MyInterface<string>
{
    public string GetSomething()
    {
        return "Something";
    }

    public void DoSomething(string something)
    {
        Console.Write(something);
    }

    public void Generically(MyInterfaceFunc func) {
        func.Call(this);
    }
}
public class MyFunc : MyInterfaceFunc {
    public void Call<T>(MyInterface<T> thingDoer) {
        T something = thingDoer.GetSomething();
        thingDoer.DoSomething(something);
        thingDoer.DoSomething(something);
    }
}

public class Program {
    public static void Main(){
        var listOfThings = new List<MyInterface>(){
            new MyIntClass(),
            new MyStringClass()
        };

        foreach (MyInterface thingDoer in listOfThings){
            thingDoer.Generically(new MyFunc());
        }
    }
}
0
votes

Since I don't know what's your underlying issue in your actual domain I can't provide a bullet-proof solution. It should be worth the effort that you should look about what's covariance and contravariance in generic parameters both on interfaces and delegates and give this approach a try refactoring your code.

For now, I believe that this should be a possible solution:

public static void DoALotOfThingsTwice()
{
    var listOfThings = new List<object>
    {
        new MyIntClass(), new MyStringClass()
    };

    MyInterface<int> a;
    MyInterface<string> b;

    // During each iteration, check if the thing is a concrete 
    // implementation of your interface MyInterface<T>...
    foreach (object thingDoer in listOfThings)
    {           
        // ...and call MyInterface<T>.DoSomething method depending on 
        // the success of the cast to MyInterface<int> or 
        // MyInterface<string> 
        if ((a = thingDoer as MyInterface<int>) != null)
            a.DoSomething(38);
        else if((b = thingDoer as MyInterface<string>) != null)
            b.DoSomething("hello world");
    }
}