我正在重新设计用于数据采集的应用程序。
我们有一个名为Sensor
的基类,它或多或少如下:
public abstract class Sensor
{
public virtual String Name { get; }
public virtual UnitOfMeasurement Unit { get; }
public virtual int SamplingRate { get; }
public virtual CalibrationModel Calibration { get; }
}
每个子类的每个属性都有一个“硬编码”值。例如EmgSensor
将“EMG”作为名称,将“UnitOfMeasurement.Volt”作为单位等等。
我们目前的系统遇到了这个问题我想解决的问题:每次开发新的实际传感器硬件并添加到我们的产品组合中时,我们都需要进行以下“猎枪手术”:
Sensor
子类; 据我所知,每个物理传感器(硬件)都是一个概念单元,因此应该能够“插入”正在运行的系统,以便不需要重新编译。
另一方面,如果要将Sensor
的每个子类型视为一个类,我怎样才能从配置文件中创建一个“动态”类?我应该使用工厂模式吗?是否还有其他更合适的方式来实现我的需求?
我正在使用C#(虽然我认为这是问题的偶然内容)。
答案 0 :(得分:1)
.NET使动态加载类型变得非常容易。我所做的只是定义一个文件夹,我删除包含新传感器的程序集。我有一个加载器类,用于加载文件夹中的程序集,然后检查它们是否为Sensor的子类,创建子类的实例并将它们返回到列表中。
CoreLibrary程序集包含抽象基类(以及它需要的任何其他内容)
namespace CoreLibrary
{
public abstract class Sensor
{
public abstract String Name { get; }
public abstract UnitOfMeasurement Unit { get; }
public abstract int SamplingRate { get; }
public abstract CalibrationModel Calibration { get; }
}
}
DynamicClassLoader是具有可以做有趣事情的加载器类的程序集。它引用了CoreLibrary ......
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Configuration;
using CoreLibrary;
namespace DynamicClassLoader
{
public class Loader
{
public List<Sensor> LoadDynamicSensors()
{
var sensors = new List<Sensor>();
if (!Directory.Exists(DynamicAssemblyFolder))
{
return sensors;
}
var dllFileNames = Directory.GetFiles(DynamicAssemblyFolder, "*.dll");
foreach (var dllFileName in dllFileNames)
{
var dynamicAssembly = Assembly.LoadFrom(dllFileName);
foreach (var sensorType in dynamicAssembly.GetTypes().Where(t => t.IsSubclassOf(typeof(Sensor))))
{
var sensor = (Sensor)Activator.CreateInstance(sensorType);
sensors.Add(sensor);
}
}
return sensors;
}
public string DynamicAssemblyFolder
{
get { return ConfigurationManager.AppSettings["DynamicAssemblyFolder"]; }
}
}
}
然后只需创建引用CoreLibrary的程序集并将其dll放在已定义的文件夹中。例如......
using CoreLibrary;
namespace DynamicOne
{
public class SensorA: Sensor
{
public override string Name
{
get { return "Sensor A"; }
}
public override UnitOfMeasurement Unit
{
get { return null; }
}
public override int SamplingRate
{
get { return 10; }
}
public override CalibrationModel Calibration
{
get { return null; }
}
}
}
并显示它适用于控制台应用程序。它仅引用CoreLibrary和DynamicClassLoader。它不需要引用动态加载的程序集,因为类型都是从Sensor派生的。
using System;
using DynamicClassLoader;
namespace DynamicLoading
{
class Program
{
static void Main(string[] args)
{
var loader = new Loader();
var sensors = loader.LoadDynamicSensors();
Console.WriteLine(loader.DynamicAssemblyFolder);
foreach (var sensor in sensors)
{
Console.WriteLine(sensor.Name);
}
Console.Read();
}
}
}
需要新类型时。创建一个新程序集,将其放入指定的文件夹并重新启动应用程序,然后加载新传感器并准备就绪。 (您可以使用文件观察器并自动执行此操作,但这可能有点过分。)
不确定如何使用传感器,但您可以在工厂中包装(或注入)装载器,以便轻松获得特定传感器。