C# foreach和泛型编译器问题
我使用了一个类似于以下内容的接口和类:C# foreach和泛型编译器问题,c#,.net,generics,compiler-construction,foreach,C#,.net,Generics,Compiler Construction,Foreach,我使用了一个类似于以下内容的接口和类: public interface IIdentity { int Id { get; set; } } public class Identity : IIdentity { public int Id { get; set; } } var identities = new List<Wrapper<IIdentity>>(); identities.Add( new Wrapper<IIdentity&
public interface IIdentity
{
int Id { get; set; }
}
public class Identity : IIdentity
{
public int Id { get; set; }
}
var identities = new List<Wrapper<IIdentity>>();
identities.Add( new Wrapper<IIdentity> { WrappedObject = new Identity { Id = 1 }, Name = "John", Order = 1 } );
identities.Add( new Wrapper<IIdentity> { WrappedObject = new Identity { Id = 2 }, Name = "Jane", Order = 2 } );
identities.Add( new Wrapper<IIdentity> { WrappedObject = new Identity { Id = 3 }, Name = "Joe", Order = 3 } );
我正在创建标识
类的实例,并将其添加到列表
(稍后称为实例创建块)
最近,我需要添加更多关于IIdentity
实例的数据,而不需要对IIdentity
和Identity
进行任何修改。因此,我添加了以下类:
public class Wrapper<T> where T : class
{
public T WrappedObject { get; set; }
public string Name { get; set; }
public int Order { get; set; }
}
第2行:
foreach ( var identity in identities )
问题是为什么编译器在修改1或2未到位时成功编译了应用程序?编译器看到
标识的类型是列表
,并且可以看到包装器
没有实现IIdentity
。但是,这本身不足以产生编译时错误,因为可能有这样的派生类:
class DerivedWrapper<T> : Wrapper<T>, IIdentity { ... }
class-derivedwapper:Wrapper,IIdentity{…}
DerivedWrapper
的实例可以合法地放在标识
中,因此编译器必须在运行时尝试将identity
强制转换为IIdentity
,如果失败,则引发异常
这两个修改以不同的方式对此产生影响:
如果包装器
是密封的
,那么编译器知道不可能有这样的派生类,因此运行时强制转换永远不会成功;有益的是,它将此升级为编译时错误
如果使用带有var
的隐式类型,则编译器将var
解析为identity
的静态类型,在本例中为Wrapper
。这意味着循环体试图访问不存在的成员Wrapper.Id
成员,因此出现编译时错误
史蒂文:这个问题不是被长镜头愚弄的。
foreach ( IIdentity identity in identities )
foreach ( var identity in identities )
class DerivedWrapper<T> : Wrapper<T>, IIdentity { ... }