来自Java世界,使用泛型和C#进行编程通常是一个令人头疼的问题.像这个:
interface ISomeObject { }
class SomeObjectA : ISomeObject { }
class SomeObjectB : ISomeObject { }
interface ISomething<T> where T : ISomeObject
{
T GetObject();
}
class SomethingA : ISomething<SomeObjectA>
{
public SomeObjectA GetObject() { return new SomeObjectA(); }
}
class SomethingB : ISomething<SomeObjectB>
{
public SomeObjectB GetObject() { return new SomeObjectB(); }
}
class SomeContainer
{
private ISomething<ISomeObject> Something;
public void SetSomething<T>(ISomething<T> s) where T : ISomeObject
{
Something = (ISomething<ISomeObject>)s;
}
}
class TestContainerSomething
{
static public void Test()
{
SomeContainer Container = new SomeContainer();
Container.SetSomething<SomeObjectA>(new SomethingA());
}
}
Run Code Online (Sandbox Code Playgroud)
这将导致到InvalidCastException的Something = (ISomething<ISomeObject>)s;.在Java中,这可以工作,我甚至可以使用(如果所有其他方法都失败)泛型通配符<?>.这在C#中是不可能的.
虽然这只是我用来解释问题的一个例子,但如何消除这种异常呢?唯一的主要限制是SomeContainer 不能成为泛型类
**注意**:关于这个问题有很多问题,但是没有一个(我能找到)解决非泛型类中的泛型类成员.
**更新**
在方法内部SetSomething,我添加了以下行:
Console.WriteLine(s.GetType().IsSubclassOf(typeof(ISomething<SomeObjectA>)));
Console.WriteLine(s.GetType().ToString() + " : " + s.GetType().BaseType.ToString());
foreach (var i in s.GetType().GetInterfaces())
{
Console.WriteLine(i.ToString());
}
Run Code Online (Sandbox Code Playgroud)
令我惊讶的输出
False
SomeThingA : System.Object
ISomething`1[SomeObjectA]
Run Code Online (Sandbox Code Playgroud)
这是我得到这个例外的原因吗?
Out关键字将是一个修复,如果你ISomething只有返回T的方法
interface ISomething<out T> where T : ISomeObject
Run Code Online (Sandbox Code Playgroud)
在创建通用接口时,您可以指定在具有不同类型参数的接口实例之间是否存在隐式转换.
它被称为协方差和逆变
Eric Lippert有一系列很好的文章,为什么我们需要考虑这个问题,这里使用了界面差异
这是我的代码,它对我来说是预期的
interface ISomeObject { }
class SomeObjectA : ISomeObject { }
class SomeObjectB : ISomeObject { }
interface ISomething<out T> where T : ISomeObject
{
T GetObject();
}
class SomethingA : ISomething<SomeObjectA>
{
public SomeObjectA GetObject() { return new SomeObjectA(); }
}
class SomethingB : ISomething<SomeObjectB>
{
public SomeObjectB GetObject() { return new SomeObjectB(); }
}
class SomeContainer
{
private ISomething<ISomeObject> Something;
public void SetSomething<T>(ISomething<T> s) where T : ISomeObject
{
Something = (ISomething<ISomeObject>)s;
}
}
class TestContainerSomething
{
static public void Test()
{
SomeContainer Container = new SomeContainer();
Container.SetSomething<SomeObjectA>(new SomethingA());
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
863 次 |
| 最近记录: |