10

In generics we can give constraints using the "where" clause like

public void MyGeneric <T>() where T : MyClass1 {...}

Now if i want the type T to be of type MyClass1 and say an interface IMyInterface then i need to do something like

public void MyGeneric <T>() where T : MyClass1, IMyInterface  {...}

But I dont know (or maybe it is not possible) if we can create a generic method that can take types which inherits from either of the 2 types. i.e. if any of my other classes inherits from MyClass1 or implements IMyInterface but neither of my class has both then my generic method should work for these classes.

I hope I have been clear.

8 Answers 8

12

You can't, and for a good reason. Say MyClass1 and IMyInterface both have a CoolThing() method (presumably such commonality is precisely why you want to do this sort of thing in the first place). You sort of want code like:

public void MyGeneric<T>(T item) where T : MyClass1 or T : IMyInterface
{
  item.CoolThing();
}

The problem with this is that as MyClass1.CoolThing() is defined completely differently to IMyInterface.CoolThing(). You may know that they do essentially the same thing, but they may be very different indeed (Employee.Fire() is presumably very different to Gun.Fire() and so on).

You've got two options that I can see. One is to define two different methods. Overloading will reduce the headache of calling them, and they could share some pieces of their implementation in a private method that doesn't depend upon the relevant features of the MyClass1 and IMyInterface signatures.

The other is to use reflection to obtain the MethodInfo of the method called "CoolThing" on the object in question, and then invoke it. This latter obviously blows away your compile time type safety.

Sign up to request clarification or add additional context in comments.

1 Comment

I also have a need for this and it makes sense and logic to have this feature! I may accept a parameter of type object but having this option I am telling the caller what I want more precisely. In my case, I want a Type or a string, because my code knows how to handle them. I firstly start from the ease of use for the caller and build code around it. Yes, I could make an overload of a method, which I will do. ;)
7

As anyone before says you cannot ceate or-constraints, but there is the clear and simple way to bypass this problem.

Put some extra interface on all the classes and interfaces that you want to be valid types for a generic arguments. Thats the solution that will let you to use them all in generic methods without leting any other to be used.

For example:

class MyClass1 : IAllowInMyGeneric { ... }
interface IMyInterface : IAllowInMyGeneric { ... }

public void MyGeneric <T>() where T : IAllowInMyGeneric {...}

1 Comment

Hi Luk, Your workaround is good but the MyClass1 in my case is a .net class and I cannot change the class to implement an interface. Any other solution if any??? Thanks for your time.
2

No, you can't. where T : MyClass1, IMyInterface is an and relationship.

There is no provision for an or relationship.

Comments

1

It is indeed not possible and for one very good reason:

interface IFoo { void A(); }
interface IBar { void B(); }

class Test<T> where T Ifoo <OR> IBar
{
    void M() {  T.A(); } // will this work?? 
}

The constraints determine what functionality the Type parameter offers. It has to be defined exactly.

1 Comment

Of course, this depends on the nature of the generics mechanism. In C++ the above would be fine, it just wouldn't let you call M() on a Test<T> parametrised by IBar. .NET generics work very differently. More pointedly, if IFoo and IBar both had a A(), then while the sort of generics in C++ would be happy, the sort in .NET wouldn't because it will still consider IFoo.A() to be different to IBar.A().
0

You cannot - from the same reason there is no multiple inheritance I guess.

2 Comments

Nope, that's a completely different mechanism, and is dis-allowed for different reasons.
Maybe - never really gave it a deep thought
0

This is not possible

Comments

0

Unfortunately, it's not possible to do it that way. To get this to work MyClass1 would have to implement the IMyInterface. In that case you probably wouldn't need generics because of the common interface.

2 Comments

He never says that MyClass implements IMyInterface. Thats why he should join them with a third interface.
True, a thrid interface would work 100% of the time. But, he also didn't say that it doesn't implement it. In my code I'd keep it simple if I can. If using the same function I'd home there was some comminality.
0

Adding on to Jon Hanna's last workaround

The other is to use reflection to obtain the MethodInfo of the method called "CoolThing" on the object in question, and then invoke it. This obviously blows away your compile time type safety.

You can use 'dynamic' and manually check the type of your arg (which is reflection under the hood). You might use this if you have no control over the Classes of the arg.

private void MyMethodThatAcceptsArgOfTwoTypes(dynamic arg)
{
    if (arg is MyClass1 || arg is IMyInterface)
    {
        arg.CoolThing(); //no type safety here, you'll get a runtime exception if this method doesn't exist.
    }
    else
    {
        throw new ArgumentException("arg is supposed to be MyClass1 or IMyInterface");
    }
    
    //example of using a method that does the same thing, but named differently:
    int someCount = arg is MyClass1 ? arg.CountInClass() : arg.CountMethodForInterface();
}

I wouldn't use this in a publicly exposed method though. It can be confusing. Rather, I'd make 2 overloaded public methods and call this private method.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.