与此问题类似:How can I require a method argument to implement multiple interfaces? 我想要一个方法参数来实现几个接口。
接口应以任意方式组合,我不想为每个有效组合创建接口。
想一个文件。它可以是:
IReadable
IWriteable
IArchive
IGenerated
...
如果我想表达一个参数需要是一个可写的,生成的存档我不想生成IWritableGeneratedArchive
,因为有太多的组合,我想用它与一些我无法修改的现有类。
伪代码:
void WriteTo( IWritable + IGenerated + IArchive file)
{
//...
}
答案 0 :(得分:8)
我在此处找到的解决方案:How can I require a method argument to implement multiple interfaces?根据C#调整。
积分转到Michael Myers
internal interface IF1
{
void M1();
}
internal interface IF2
{
void M2();
}
internal class ClassImplementingIF1IF2 : IF1, IF2
{
public void M1()
{
throw new NotImplementedException();
}
public void M2()
{
throw new NotImplementedException();
}
}
internal static class Test
{
public static void doIT<T>(T t) where T:IF1,IF2
{
t.M1();
t.M2();
}
public static void test()
{
var c = new ClassImplementingIF1IF2();
doIT(c);
}
}
答案 1 :(得分:3)
通常的+约束?
void WriteTo<T>( T file) where T : IWritable,IGenerated,IArchive
{
//...
}
答案 2 :(得分:2)
使用通用约束:
void WriteTo<T>(T file) where T: IWritable, IGenerated, IArchive
{
//...
}
答案 3 :(得分:0)
我不想生成IWritableGeneratedArchive,因为它有太多的组合
组合太多了?无论有多少潜在组合,您只需要为实际用作方法参数的组合创建一个组合界面,此时您无论如何都要将它全部写出来。换句话说,实际上并没有那么多工作。
我想将它用于一些我无法修改的现有类。
IWritableGeneratedArchive类型可以传递给只需要IArchive或IWritable的东西。这仍然适用于您已经拥有的任何其他东西。
但是既然你已经决定反对这一点,看起来你已经在这个架构上投入了很多,我想知道你是否见过 Code Contracts 。他们看起来可能会做你需要的。
答案 4 :(得分:0)
这个解决方案试图将supercat的想法与存储这样的“多接口”对象结合起来。
我通过将它们存储在公开所描述的对象接口的Holder
类中来完成此操作。
Holder
个对象可以存储并且是预期的参数。缺点是你必须首先创建Holder
并且Holder
的类型参数的顺序很重要。
从好的方面来说,你也可以动态创建Holder
,当然也可以存储“多界面”对象。
启用holder.Get<T>()
方法(比holder.t1好)但它不会编译会很好。
也许有人知道如何修复它?我认为需要添加约束T1
不是T2
,反之亦然。此接缝与C# generic does *not* implement something相关,但他们没有找到解决方案。
internal interface IF1
{
void M1();
}
internal interface IF1_extension : IF1
{
}
internal interface IF2
{
void M2();
}
internal class ClassImplementingIF1IF2 : IF1_extension, IF2
{
public void M1()
{
throw new NotImplementedException();
}
public void M2()
{
throw new NotImplementedException();
}
}
internal interface Getter<T> where T : class
{
T Get();
}
internal class Holder<T1, T2> //: Getter<T1>, Getter<T2> // not possible since T1 and T2 may be the same => won't compile!
where T1 : class
where T2 : class
{
private Holder(T1 t1, T2 t2)
{
Debug.Assert(t1 != null, "Argument is no " + typeof(T1).Name);
Debug.Assert(t2 != null, "Argument is no " + typeof(T2).Name);
this.t1 = t1;
this.t2 = t2;
}
public static Holder<T1, T2> CreateFrom<T>(T t) where T : T1, T2
{
return new Holder<T1, T2>(t, t);
}
public static Holder<T1, T2> CreateDynamicallyFrom(object t)
{
return new Holder<T1, T2>(t as T1, t as T2);
}
public readonly T1 t1;
public readonly T2 t2;
//T1 Getter<T1>.Get()
//{
// return t1;
//}
//T2 Getter<T2>.Get()
//{
// return t2;
//}
}
internal class Holder<T1, T2, T3> // Holder<T1,T2,T3,T4> etc. are defined in a similar way
where T1 : class
where T2 : class
where T3 : class
{
private Holder(T1 t1, T2 t2, T3 t3)
{
Debug.Assert(t1 != null, "Argument is no " + typeof(T1).Name);
Debug.Assert(t2 != null, "Argument is no " + typeof(T2).Name);
Debug.Assert(t3 != null, "Argument is no " + typeof(T3).Name);
this.t1 = t1;
this.t2 = t2;
this.t3 = t3;
}
public static Holder<T1, T2,T3> CreateFrom<T>(T t) where T : T1, T2, T3
{
return new Holder<T1, T2, T3>(t, t, t);
}
public static Holder<T1, T2, T3> CreateDynamicallyFrom(object t)
{
return new Holder<T1, T2, T3>(t as T1, t as T2, t as T3);
}
public readonly T1 t1;
public readonly T2 t2;
public readonly T3 t3;
}
internal static class Test
{
public static void doIt<T>(T t) where T : IF1, IF2
{
t.M1();
t.M2();
}
public static void doIt(Holder<IF1, IF2> t) // Interfaces should be mentioned in alpahbetical order since Holder<IF1,IF2> != Holder<IF2,IF1>
{
t.t1.M1();
t.t2.M2();
}
public static void doIt_extended<T1, T2>(Holder<T1, T2> t) // handles conversions from Holder<T1,T2> to Holder<T1 or base of T1, T2 or base of T2>
where T1 : class, IF1
where T2 : class, IF2
{
t.t1.M1();
t.t2.M2();
}
public static void test()
{
var c = new ClassImplementingIF1IF2();
doIt(c);
var c_holder = Holder<IF1, IF2>.CreateFrom(c);
doIt(c_holder);
var another_c_holder = Holder<IF1_extension, IF2>.CreateFrom(c);
doIt_extended(another_c_holder);
object diguised_c = c;
var disguised_c_holder = Holder<IF1, IF2>.CreateDynamicallyFrom(diguised_c);
doIt(disguised_c_holder);
}
}