Я не одобряю эту практику, но есть два варианта, которые другие не упомянули:
Если вы контролируете foo
Тогда вы можете изменить его на:
void foo(IA asA, IB asB)
{
if (!ReferenceEquals(isA, isB)) throw new ArgumentException("isA and isB must be the same object");
// Your code here
}
Это позволяет вашему телефонному коду стать:
foo(obj as IA, obj as IB);
Это не красиво, но это может быть вариант.
Если вы любите пандемические хаки
Если вам часто приходится этим заниматься, то это неприятный запах и лучший дизайн.
Но если у вас нет выбора, и это "необходимо" повсеместнотогда это может сделать вашу жизнь проще, потому что вам не нужно тратить время на создание классов, которые реализуют ваши интерфейсы IA
и IB
:
/// <summary>
/// An ugly hack for when you don't want to create a new wrapper class that inherits from and implements two other interfaces
/// </summary>
/// <typeparam name="TOne"></typeparam>
/// <typeparam name="TTwo"></typeparam>
public sealed class MultiType<TOne, TTwo>
{
/// <summary>
/// The contained item
/// </summary>
private readonly object _containedObject;
/// <summary>
/// The contained item as a TOne
/// </summary>
public TOne AsOne => (TOne)_containedObject;
/// <summary>
/// The contained item as a TTwo
/// </summary>
public TTwo AsTwo => (TTwo)_containedObject;
/// <summary>
/// Creates a new MultiType that exposes the given item as two different classes
/// </summary>
/// <param name="containedObject"></param>
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");
}
/// <summary>
/// Creates a new MultiType that exposes the given thing as both a TOne and a TTwo
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="thing"></param>
/// <returns></returns>
public static MultiType<TOne, TTwo> Create<T>(T thing)
where T : TOne, TTwo
=> new MultiType<TOne, TTwo>(thing);
}
Использование:
void foo(MultiType<IA, IB> 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<IA, IB>.Create(obj))
Обратите внимание, что это может быть "цепочкой": экземпляр MultiType<MultiType<IDictionary<string, string>, IList<int>>, MultiType<INotifyPropertyChanged, INotifyCollectionChanged>
позволит вам иметь дело с вещью в виде словаря, списка целых чисел, простого перечисления, INotifyPropertyChanged и INotifyCollectionChanged,все сразу.
Но опять же, это действительно плохой кодll - вероятно, класс, с которым нужно иметь дело таким образом, делает слишком много.