【发布时间】:2014-09-23 01:57:37
【问题描述】:
更新:
我会接受让代码工作Jon's answer to this other question 是正确的。 this answer 回答了为什么接口被视为引用类型。
我还是想知道有什么区别。当接口是泛型类型约束时,为什么不将接口视为引用类型?这是他们的一些设计原因吗?我有一种感觉,唯一的原因可能是“他们就是这样”。
原问题:
我正在将一个类转换为泛型类,但我发现使用接口作为类型参数时出现了一些奇怪的行为。该类有一个字段和属性,它们是一种接口类型,例如 IMagic。
public interface IMagic
{
bool Magic { get; }
}
public class HasMagic
{
private IMagic _magic;
public IMagic Magic
{
get { return _magic; }
set
{
if (value != _magic)
_magic = value;
}
}
public bool IsMagical
{
get { return _magic != null ? _magic.Magic : true; }
}
}
我想将它们改为类型 T 并使用类型参数 where T : IMagic 定义类。这样做虽然给了我一个编译器错误Operator '!=' cannot be applied to operands of type 'T' and 'T'。
public class HasMagic<T> where T : IMagic
{
private T _magic;
public T Magic
{
get { return _magic; }
set
{
// Compiler error here!
if (value != _magic)
_magic = value;
}
}
public bool IsMagical
{
// But no error here!?
get { return _magic != null ? _magic.Magic : true; }
}
}
那么为什么通用版本不起作用? == 和 != 运算符不应该适用于所有类型吗?
该错误只发生在属性设置器中,所以它让我想到,_magic 字段实际上是盒装的 IMagic 还是其他一些引用类型?事实上,它可以设置为 null ,这应该只适用于可为空的类型。正如下面的测试所示,IMagic 结构 (MagicStruct) 工作正常,但为什么呢?如您所料,将 HasMagic 中的字段和属性更改为 MagicStruct 会产生编译错误。
public class MagicTests
{
[Fact]
public void SomeMagicTest()
{
var mag = new HasMagic();
Assert.True(mag.IsMagical);
mag.Magic = new MagicClass();
Assert.False(mag.IsMagical);
mag.Magic = new MagicStruct();
Assert.True(mag.IsMagical);
mag.Magic = null;
Assert.True(mag.IsMagical);
}
}
public class MagicClass : IMagic
{
public bool Magic { get { return false; } }
}
public struct MagicStruct : IMagic
{
public bool Magic { get { return true; } }
}
如果有任何相关性,我正在使用 .Net framework v4.5.2。
【问题讨论】:
-
“那么为什么通用版本不起作用?== 和 != 运算符不应该适用于所有类型吗?”见stackoverflow.com/questions/390900/…
-
1:
T可能有也可能没有定义==和!=运算符。 2:if (value != _magic)是多余的 -
@IlyaLuzyanin 我明白这一点。但是如果只使用应该有同样问题的接口,它就可以正常工作。