如何摆脱用于属性的空接口

时间:2018-03-22 09:16:28

标签: c# interface attributes

我有一个代表工厂传感器的类。由于历史原因,类似的对象(因此由同一个类表示)具有不同的标识:

  • 有些人有一个名字(即“north-west-gummy-bear”)
  • 有些人有一个areaId和一个sensorId

为了适应这种情况,我使用了一个空接口:

public class sensor
{
    ISensorIdentifier id{get;set;}
}

public interface ISensorIdentifier{

}


public class namedSensorID:ISensorIdentifier{
    string name{get;set;}
}

public class idSensorID:ISensorIdentifier{
    int areaID{get;set;}
    int sensorID{get;set;}
}

这允许我对具有不同识别系统的对象使用相同的类。

据我所知,空接口是代码气味,我应该使用自定义属性。

但是,在阅读自定义属性后,我不知道从哪里开始。实际上,我可以使用自定义属性“sensorIdentifier”而不是空接口,但是如何在id类中键入sensor属性?

2 个答案:

答案 0 :(得分:1)

您可以认为传感器有一个唯一的有效标识符信息(使用c#7本机元组支持):

(Name, AreaId, SensorId)

您的业务逻辑应强制执行有效的ID信息:

(Name, null, null)

(null, AreaId, SensorId)

其他任何内容均无效。好的,让我们构建一个强制执行此操作的基类:

public abstract class Sensor
{
     private readonly string name;
     private readonly int? areaId, sensorId;

     protected Sensor(string name)
     {
         this.name = name;
     }

     protected Sensor(int areaId, int sensorId)
     {
         this.areaId = areaId;
         this.sensorId = sensorId;
     }

     public (string Name, int? AreaId, int? SensorId) Id
     {
          get
          {
              Debug.Assert(
                  (name != null && !(areaId.HasValue || sensorId.HasValue)) ||
                  (name == null && (areaId.HasValue && sensorId.HasValue)));
              return (name, areaId, sensorId);
          }
     }
}

您的特定传感器实施是微不足道的,扩展了Sensor

public class NamedSensor: Sensor
{
    public NamedSensor(string name)
        :base(name)
    { }
}

public class IdSensor: Sensor
{
    public IdSensor(int areaId, int sensorId)
        :base(areaId, sensorId)
    { }
}

您可以愉快地使用IEnumerable<Sensor>

答案 1 :(得分:0)

我建议你在空接口中添加一个唯一标识符,该标识符应该在每个具体类中实现:

public interface ISensorIdentifier
{
    string UniqueSensorId { get; }
}

您应该确保不同子类中的这些实现使这个新ID唯一。这是一个快速提案:

public class namedSensorID : ISensorIdentifier
{
    public string UniqueSensorId { get { return nameof(namedSensorID) + name; } }

    string name { get; set; }
}

public class idSensorID : ISensorIdentifier
{

    int areaID { get; set; }
    int sensorID { get; set; }
    public string UniqueSensorId { get { return nameof(idSensorID) + areaID + sensorID; } }
}