I want to call a generic method that constrains the input type T to implement two interfaces:
interface IA { }
interface IB { }
void foo(T t) where
I'm not condoning this practice, but here are two options that others didn't mention:
fooThen you can refactor it to:
void foo(IA asA, IB asB)
{
if (!ReferenceEquals(isA, isB)) throw new ArgumentException("isA and isB must be the same object");
// Your code here
}
This allows your calling code to become:
foo(obj as IA, obj as IB);
It isn't pretty, but it might be an option.
If you find yourself needing to do this a lot, then that's a bad smell and there's a better design.
But if you have no choice and this is "needed" all over the place, then this might make your life easier because you don't have to waste time creating classes that implement your IA and IB interfaces:
///
/// An ugly hack for when you don't want to create a new wrapper class that inherits from and implements two other interfaces
///
///
///
public sealed class MultiType
{
///
/// The contained item
///
private readonly object _containedObject;
///
/// The contained item as a TOne
///
public TOne AsOne => (TOne)_containedObject;
///
/// The contained item as a TTwo
///
public TTwo AsTwo => (TTwo)_containedObject;
///
/// Creates a new MultiType that exposes the given item as two different classes
///
///
private MultiType(object containedObject)
{
if (containedObject is TOne && containedObject is TTwo)
_containedObject = containedObject;
else
throw new Exception("The given object must be both a TOne and a TTwo");
}
///
/// Creates a new MultiType that exposes the given thing as both a TOne and a TTwo
///
///
///
///
public static MultiType Create(T thing)
where T : TOne, TTwo
=> new MultiType(thing);
}
Usage:
void foo(MultiType thing)
{
thing.AsOne... // Your code dealing with the thing as an IA
thing.AsTwo... // Your code dealing with the thing as an IB
}
Caller:
foo(MultiType.Create(obj))
Note that this can be "chained": an instance of MultiType would let you deal with a thing as a dictionary, list of integers, plain enumerable, INotifyPropertyChanged, and INotifyCollectionChanged, all at once.
But again, it's a really bad code smell--likely the class that needs to be dealt with in that way is doing way too much.