2016-11-24 53 views
0
public interface IFoo { } 
public abstract class IFooDerived : IFoo { } 
public class Foo : IFooDerived { } 

public interface IBar { } 
public abstract class IBarDerived : IBar { } 
public class Bar : IBarDerived { } 

public interface IExample<out A, B> where A : IFoo where B : IBar 
{ 
    A Foo(B b); 
} 

public class Example : IExample<Foo, Bar> 
{ 
    static Example example = new Example(); 
    static Example() 
    { 
     Example ex = example; 

     IExample<IFoo, IBar> ex_huh = ex; //How can I do this? 

     //Or is there a way where I can say I don't care, but I still want to reference ex, like this: 
     IExample<object,object> ex_huh2 = ex; 
     //Or: 
     IExample<, > ex_huh2 = ex; 

     ex_huh2.Foo(new Bar()); //And still call Foo? 
    } 

    public Foo Foo(Bar b) 
    { 
     throw new NotImplementedException(); 
    } 
} 

在上面的例子中,我如何在不知道其泛型类型的情况下对静态示例变量进行降级和引用,但仍能够调用“A Foo(B b)”?c#协议属性/通用访问的泛型?

是否有这样做的强类型的方式?

回答

1
IExample<IFoo, IBar> ex_huh = ex; //How can I do this? 

你不能,因为它会破坏类型安全。这是因为你试图使你的方法的参数类型(该参数为Foo(B b))更一般化,这是不安全的。

为了更容易理解为什么这是一个问题,让我们熬你的榜样下来的东西当量(只要该方法参数云):

function DoSomethingWithFoo(Foo foo) { ... } 
// The following line won't compile, but let's pretend it does and see what happens 
Action<IFoo> doSomethingWithIFoo = DoSomethingWithFoo; 
doSomethingWithIFoo(new OtherFoo()); 

其中OtherFoo是实现IFoo一些其他类,但不会从Foo类下降。

哎呦!你打电话DoSomethingWithFoo,它预计Foo的实例,但通过OtherFoo而不是!古怪的hijinks随之而来。

这是本质你想在你的例子做什么。您正在尝试使用期望类型为Foo的参数的方法,并将其转换为可让您通过任何IFoo的方法。

(这就是为什么编译器不会让你声明的IExampleB类型参数为out B,这是它必须是让你施放一个IExample<..., Foo>IExample<..., IFoo>。编译器看到的是,B类型参数作为一个方法参数的类型,并因此使其协变会破坏类型安全)


至于如何完成你在找什么:那将依赖。你想要的具体例子做

IExample<...figure out how to declare this...> = ...any IExample<A, B>...; 
ex_huh2.Foo(new Bar()); 

是不会在一般的工作,因为“......任何IExample<A, B> ......”很可能是一个IExample<..., OtherBar>,然后你不能传递一个new Bar()。你必须弄清楚你想如何解决这个冲突。

也许你确实想在new Bar()通过,在这种情况下,也许你想这样做,多数民众赞成限制为只与Bar服用IExample S作为他们的第二个类型参数的方法中:

public void AddABar<TFoo>(IExample<TFoo, Bar> example) 
{ 
    example.Foo(new Bar()); 
} 

或者也许你想创建一个新的实例不管的第二个类型参数是:

public void AddAThing<TFoo, TBar>(IExample<TFoo, TBar> example) 
    where TBar : new() 
{ 
    example.Foo(new TBar()); 
} 

或者,也许你想IExample<A, B>从非通用下降0声明一个非通用的Foo(IBar b),在你的Example类上实现该非泛型方法,并在该方法内执行一个类型转换为B - 如果在运行时将错误类型传入该方法,得到一个InvalidCastException

这实际上都归结为你想如何解决这个冲突的“我想把这个东西我可以通过new Bar()”的冲突,当事实上任何给定的实施IExample<A, B>不一定能够接受new Bar()作为方法参数。