是否有任何类型安全的,编译时检查可能引用实现多个接口的值?
鉴于
interface A {
void DoA();
}
interface B {
void DoB();
}
我能够为实现A
或 B
的对象编写代码,但不能同时编写。{p>所以我想出了丑陋的包装纸:
class ABCollection {
private class ABWrapper : A, B {
private readonly A a;
private readonly B b;
public static ABWrapper Create<T>(T x) where T : A, B {
return new ABWrapper { a = x, b = x };
}
public void DoA() {
a.DoA();
}
public void DoB() {
b.DoB();
}
}
private List<ABWrapper> data = new List<ABWrapper>();
public void Add<T>(T val) where T : A, B {
data.Add(ABWrapper.Create(val));
}
}
在不丢失类型安全性(运行时强制转换等)的情况下,是否有更直观地编写此代码的技巧?
E.g。
private List<A and B> ...
编辑:这不是特别关注列表 - 我只想提供一个存储此类值的“完整”示例。我的问题只是如何键入两个接口的组合(例如A & B
或A and B
)。
另一个更有用的示例:List<IDrawable & IMovable>
...
答案 0 :(得分:7)
您可以像在C#中那样执行参数多态,但不能执行子类型多态。也就是说,您可以创建一个多态方法,如:
void Foo<T>(T t) where T : IFoo, IBar
{
t.Foo();
t.Bar();
}
然后你必须传递一个在编译时类型已知的对象来实现IFoo和IBar。
但是没有办法说出来
void Foo(IFoo-and-IBar t)
{
t.Foo();
t.Bar();
}
然后传入一个既是IFoo又是IBar的值。整洁的功能,但不是我们支持的功能。
答案 1 :(得分:1)
好吧,正如Eric Lippert所说,没有IFoo-and-IBar
类型可以用作方法参数类型。
然而,我正在尝试一些想法,并想出了另一种使用你的包装类的方法,可能更好。我会把这个留给你(或者其他人可能会搜索这个问题)来决定:
<强>类强>
public abstract class ABWrapper : IA, IB
{
private readonly IA a;
private readonly IB b;
protected ABWrapper( IA a, IB b ) { this.a = a; this.b = b; }
// Implement methods on IA and IB
}
public sealed class ABWrapper<T> : ABWrapper
where T : IA, IB
{
private ABWrapper( T a, T b ) : base( a, b ) { }
public static implicit operator ABWrapper<T>( T t )
{
if ( t == null ) return null;
return new ABWrapper<T>( t, t );
}
}
示例强>
public class AB : IA, IB { }
void Method( ABWrapper x )
{
}
void Main()
{
AB x = null;
Method( (ABWrapper<AB>) x );
}
关于这个问题,你需要在每个呼叫站点对ABWrapper<T>
进行投射。您还可以创建一个扩展方法ABWrapper ToABWrapper<T>(this T t) where T : IA, IB
来替换强制转换,如果更可取的话。
如果编译器可以推断通过AB
的隐式转换存在从ABWrapper
到ABWrapper<T>
的隐式转换,那将会很酷。然而,可能有一个非常好的理由不会尝试这样做。
但是,您获得的是能够在整个方法参数中放置ABWrapper
而无需对方法进行通用化。
答案 2 :(得分:0)
我不清楚你为什么要这样做。如果你这样做,你可以声明一个基本接口:
interface AorB {}
interface A : AorB {
void DoA();
}
interface B : AorB {
void DoB();
}
并将其存储在集合中。当然,在检索时你必须使用is或as-cast(标准扩展方法可以在这里提供帮助)。
在我看来,这可能违反了SRP,而且这个集合做得太多了。或者,界面太精细了。