Reputation: 12670
Suppose I have the following class hierarchy:
Class A {...}
Class B : A {...}
Class C : A {...}
What I currently have is
Class D<T> where T : A {...}
but I'd like something of the form
Class D<T> where T in {B,C}
This is due to some odd behavior I'm not responsible for where B and C have common methods which aren't in A, but it would be nice to be able to call them in D on T.
Note: I don't have access to A,B or C to edit them
Upvotes: 37
Views: 25340
Reputation: 138007
First, If B and C have common methods, it is a design flaw they don't share an interface. That said, you can fix that even without having access to B and C.
It is possible to create a common interface. Suppose you have:
public class A
{
}
public class B : A
{
public void Start() { }
}
public class C : A
{
public void Start() { }
}
You can create a common interface:
public interface IStartable
{
void Start();
}
And use it on derived classes from B and C:
public class BetterB : B, IStartable
{
}
public class BetterC : C, IStartable
{
}
You may not be able to achieve that if you get B and C instances as is, but it can be considered if you create them. In fact, with specialized classes of B and C, you may use the interface instead of D<T>
.
Upvotes: 12
Reputation: 85976
Since you don't have access to the source, the only real answer (unless you are willing to lose safety by using dynamic
) is explicitly check for B
/C
and cast.
Upvotes: 1
Reputation: 52518
Some options:
IderivedFromA
that contain the common methods from B
and C
.D
cast T
to dynamic
and call the methods dynamicallyD
test if the you deal with an B
or C
, cast, and callD<T>
for B
and C
, these can call the methods from B
and C
directly. (Didn't think of this one myself).B
or C
, and does not use the abstract A
to use D<A>
. Instead it should use DB
or DC
. But I think this is the case, otherwise you didn't need generics.Upvotes: 2
Reputation: 128317
This isn't directly possible.
As others suggest, you could define an interface and implement it in both B
and C
.
If this isn't an option (e.g., if these classes are beyond your control), what I might suggest is this: first, start with an abstract class that includes all the functionality you can achieve with any T
deriving from A
. Then say you have some methods that exist for both B
and C
that aren't a part of A
. In D
you can make these abstract methods to be implemented by subclasses:
public abstract class D<T> where T : A
{
protected T _member;
public void DoSomethingAllTsCanDo()
{
_member.DoSomething();
}
public abstract void DoSomethingOnlyBAndCCanDo();
}
Then you can inherit from the base class for each type B
and C
and override the abstract method(s) to provide the appropriate functionality:
public class DB : D<B>
{
public override void DoSomethingOnlyBAndCCanDo()
{
_member.DoSomethingOnlyBCanDo();
}
}
public class DC : D<C>
{
public override void DoSomethingOnlyBAndCCanDo()
{
_member.DoSomethingOnlyCCanDo();
}
}
Upvotes: 9
Reputation: 2665
The where constrain in C# does not allow you to specify multiple classes as a choice. Also if you will specify multiple where contains, then they both has to be satisfied. There is no OR logic for constrain. Here is specification: http://msdn.microsoft.com/en-us/library/bb384067.aspx
Answers from Grzenio seems right for you. Extract common behavior into the common interface for B and C. Then you can use that interface as a constrain.
Upvotes: 1
Reputation: 36649
You need to define an interface for the common methods that are in B and C (lets call it Ibc), make B and C implement this interface, and then you can write:
Class D<T> where T : A, Ibc {...}
Upvotes: 28
Reputation: 9160
Do B and C implement the same interface? That may be a better route.
Upvotes: 3