如果它很混乱,我道歉。
我有两个主要接口。首先是ISensor
界面:
public interface ISensor<TReading>
where TReading : ISensorReading<ISensor<TReading>>
{
event SensorReadingCompletedEH<ISensor<TReading>, TReading> ReadCompleted;
TReading Read();
}
第二个界面:ISensorReading
:
public interface ISensorReading<TSensor>
where TSensor : ISensor<ISensorReading<TSensor>>
{
TSensor Sensor { get; }
}
导致以下错误:
类型ISensor&lt; TReading&gt;必须可兑换成
ISENSOR&LT; ISensorReading&LT; ISENSOR&LT;踩踏&GT;&GT;&GT;为了在通用类型或方法中使用它作为参数TSensor ISensorReading&lt; TSensor&gt;
和
类型ISensorReading&lt; TSensor&gt;必须可转换为ISensorReading&lt; ISensor&lt; ISensorReading&lt; TSensor&gt;&gt;&gt;为了在通用类型或方法中使用它作为参数TReading ISensor&lt; TReading&gt;
我担心这是由于在编译时无法解决的循环引用;但是我想确保像TelemetricSensor这样的派生类型的一致性:ISensor<TelemetricReading>
和
TelemetricReading:ISensorReading<TelemetricSensor>
我应该使用哪些其他方法来进行简单的投射和类型安全?
我正在使用.NET 2.0和VS2005
答案 0 :(得分:1)
你是对的 - 你不能用这种方式使用泛型类型约束来定义它们,因为它会导致无限的嵌套。
你可以做的是拥有一个或另一个的具体实现,例如:
public interface ITelemetricSensorReading : ISensorReading
然后约束传感器以强制执行:
public interface ITelemetricSensor<TReading> : ISensor<TReading> where TReading : ITelemetricSensorReading
答案 1 :(得分:1)
说,你定义了两种类型:
class AReading : ISensorReading<ASensor> { }
class ASensor : ISensor<AReading> { }
现在,声明ISensorReading<ASensor>
是非法的,因为ASensor
没有实现ISensor<ISensorReading<ASensor>>
。相反,它实现了ISensor<Areading>
,这是不同的。
请参阅,在.NET中,语句A : B
通常不会暗示语句I<A> : I<B>
。如果你仔细考虑,这不一定是真的 - 取决于I
的性质。
您正在寻找的功能称为“协方差”和“逆变”。这是C#的另一个特性,你可以告诉编译器,对于你的特定接口I
,上述含义实际上是保持(协方差),或反向含义I<B> : I<A>
成立(逆变) )。
使用out
关键字实现的第一个:
interface I<out T> { ... }
第二个 - 使用in
关键字:
interface I<in T> { ... }
不幸的是,泛型类型参数的协方差和逆变只是在C#4.0中引入,所以你在这里运气不好。
您可以升级到C#4.0(这是我强烈推荐的),或者您可以依靠单元测试来确保所有类型保持一致。
答案 2 :(得分:0)
感谢大家的回答。
最后,这是我为问题选择的解决方案。希望有用。如果你有意见或知道如何在不改变框架的情况下取得成功,请告诉我。
首先,我创建了一个具有最低要求的ISensor接口。之后我定义了一个新的ISensor通用接口,如下所示:
public delegate void SensorErrorEventHandler<TSensor>(TSensor sensor, ISensorError error)
where TSensor : ISensor;
public delegate void SensorReadingCompletedEventHandler<TSensor, TReading>(TSensor sensor, TReading[] read)
where TSensor : ISensor
where TReading : ISensorReading<TSensor>;
public interface ISensor : IDisposable
{
bool IsOpen { get; }
bool Started { get; }
void Connect();
void Disconnect();
void Start();
void Stop();
}
public interface ISensor<TSensor, TReading> : ISensor
where TSensor : ISensor
where TReading : ISensorReading<TSensor>
{
TReading[] LastReadings { get; }
event SensorErrorEventHandler<TSensor> Error;
event SensorReadingCompletedEventHandler<TSensor, TReading> ReadCompleted;
bool Read(out TReading[] readings);
}
public interface ISensorReading<TSensor> where TSensor : ISensor
{
TSensor Sensor { get; }
bool Mistaken { get; }
}
定义了theese接口并遵循相同的结构,我能够做出第一个实现:一个TelemetricSensor类及其相应的ITelemetricReading
public delegate void TelemetricSensorThresholdExceededEventHandler<TSensor>(TSensor sensor)
where TSensor : ITelemetricSensor;
public interface ITelemetricSensor : ISensor
{
/* Properties, events and methods */
}
public interface ITelemetricReading : ISensorReading<ITelemetricSensor>
{
/* Properties, events and methods */
}
public abstract class TelemetricSensor<TSensor, TReading> : ITelemetricSensor, ISensor<TSensor, TReading>
where TSensor : ITelemetricSensor
where TReading : ITelemetricReading, ISensorReading<TSensor>
{
public abstract TReading[] LastReadings { get; }
public event SensorErrorEventHandler<TSensor> Error;
public event SensorReadingCompletedEventHandler<TSensor, TReading> ReadCompleted;
public abstract bool Read(out TReading[] readings);
}
这里对TelemetricSensor抽象类的TReading很有趣。它被定义为
TReading : ITelemetricReading, ISensorReading<TSensor>
这似乎是多余的,因为ITelemetricReading继承自ISensorReading,但需要编译代码并满足两者的要求
TReading[] LastReadings { get; }
属性和
bool Read(out TReading[] readings);
方法。最后,为了跳过繁琐的转换(也许是一些错误),可以完成多次Read(...)重载,这样每个都可以正确地提供数据并满足所有接口实现。