Home > Net >  Unknown Generic in C#
Unknown Generic in C#

Time:04-07

I got the following Problem:

Is there a way to get all Classes that implement the IMatcher Interface in a List ? The Generics T U cannot be set as Unknown. In Java we can use the "?", but in C# there is no Operator for this.

public interface IMatcher<T, U>
{
}

class X1: IMatcher<string, string>
{
} 

class X2: IMatcher<string, DateTime>
{
}

class Program
{
    static void Main(string[] args)
    {
        List<IMatcher<>> l = new List(); //NOT WORKING
        l.add(new X1());
        l.add(new X2());
    }
    
}   

CodePudding user response:

You want "all Classes that implement the IMatcher Interface". But in fact, there is no IMatchter interface. There is only IMatcher<T,U>, which is to be precise not an interface. This notation is a shortcut, from which the compiler will be able to create a lot of different interfaces like IMatcher<string,string>, IMatcher<string,DateTime>, etc.

IMatcher<string,string> is a completely different type than IMatcher<string,DateTime>, hence X1 and X2 don't have a common base type! You need a common non-generic base type if you want to do that. It might look like this:

public interface IMatcher
{
    bool Match(object first, object second);
}

public interface IMatcher<T, U> : IMatcher
{
   bool Match(T first, U Second);
}

class X1: IMatcher<string, string>
{

   public bool Match(object first, object second)
   {
       return Match((string) first, (string) second);
   }

   public bool Match(string first, string second)
   {
       return true;
   }
} 

class X2: IMatcher<string, DateTime>
{
public bool Match(object first, object second)
   {
       return Match((string) first, (DateTime) second);
   }

   public bool Match(string first, DateTime second)
   {
       return true;
   }
}

Then you can store instances of X1 and X2 in common list, but you lose the advantages of generics. You have to decide if this approach makes sense in your case.

CodePudding user response:

IMatcher<string, string> and IMatcher<string, DateTime> are as far as the compiler is concerned two different types. So there are no way to store X1 and X2 in the same list. Consider for example if the interface had a property U MyProperty {get;set;}, and you wanted to do l[0].MyProperty what should the type be? a string or a DateTime? Since it could be either it is simply not allowed.

One way to provide a workaround is to add a non-generic common interface, public interface IMatcher {} that IMatcher<T, U> derives from. Or a IMatcher<T>, since both X1 and X2 have the same T-parameter type.

You could possibly also use a List<object>, but then you lose the static typing. There is also dynamic, but that completely turns of type checking.

  • Related