C# 此方法返回的System.Object类是否为反模式?

C# 此方法返回的System.Object类是否为反模式?,c#,C#,我在一个自动化团队工作,为电子元件设计测试。我们的框架非常需要的一件事是为工作台上的各种测试设备的驱动程序对象提供一个单一的源点(目前,驱动程序对象的创建非常简单) 基本上,想法是有一个对象,基于配置文件构造,这是所有其他测试代码基于名称字符串获取驱动程序对象的唯一位置。我在这里称之为“驱动源” 问题是,这些驱动程序根本不提供类似的接口。一种可能是电源(使用“设置电压”和“设置电流限制”等方法),而另一种可能是数字万用表(使用“读取电压”或“读取电流”等方法) 我提出的最佳解决方案是使用具有以下

我在一个自动化团队工作,为电子元件设计测试。我们的框架非常需要的一件事是为工作台上的各种测试设备的驱动程序对象提供一个单一的源点(目前,驱动程序对象的创建非常简单)

基本上,想法是有一个对象,基于配置文件构造,这是所有其他测试代码基于名称字符串获取驱动程序对象的唯一位置。我在这里称之为“驱动源”

问题是,这些驱动程序根本不提供类似的接口。一种可能是电源(使用“设置电压”和“设置电流限制”等方法),而另一种可能是数字万用表(使用“读取电压”或“读取电流”等方法)

我提出的最佳解决方案是使用具有以下声明的方法:

public object GetDriver(string name);
然后,使用我的“DriverSource”对象的测试代码将调用该方法,然后将System.object强制转换为正确的驱动程序类型(或者更准确地说,正确的驱动程序接口,如IPowerSupply)

我认为这样的转换是可以接受的,因为无论测试代码将要使用这个驱动程序,都最好知道接口是什么。但我希望能得到一些信息,知道这是否是一种反模式在等着咬我。如果有更好的模式来解决这个问题,我们也将不胜感激


最后一点注意:我认为这是显而易见的,但对于这个问题来说,性能基本上不是问题。获取驱动程序在一次可能持续数小时的测试运行中会发生不到100次。

如果您已经知道类型,并且无论如何都要强制转换到接口或类,那么更好的方法是将方法调用交给类型参数

public T GetDriver<T>(string name);
public T GetDriver(字符串名);
然后,可以使用工厂模式从方法返回适当类型的对象

public T GetDriver<T>(string name)
{
    switch(typeof(T).Name)
    {
        case "Foo":
            // Construct and return a Foo object
        case "Bar":
            // Construct and return a Bar object
        case "Baz":
            // Construct and return a Baz object
        default:
            return default(T);
    }
}
public T GetDriver(字符串名称)
{
开关(类型(T).名称)
{
案例“Foo”:
//构造并返回一个Foo对象
案例“酒吧”:
//构造并返回一个Bar对象
案例“Baz”:
//构造并返回一个Baz对象
违约:
返回默认值(T);
}
}
用法:

var driver = GetDriver<Foo>(someString); // Returns a Foo object
var-driver=GetDriver(someString);//返回一个Foo对象

如果你真的想让它变得通用,我会使用工厂模式

让我们从识别类型结构开始:

public interface IDriver
{
}

public interface IPowerSupply : IDriver
{
    void SetVoltage();
    void SetCurrent();
}

public interface IMultimeter : IDriver
{
    double MeasureVoltage();
}
您可以根据需要将其添加到或从中删除。现在,我们需要一种让工厂自动发现正确类型并向其提供配置信息的方法。因此,让我们创建一个自定义属性:

public class DriverHandlerAttribute : Attribute
{
    public Type DriverType { get; set; }
    public string ConfigurationName { get; set; }
}
然后我们需要一个存储配置数据的地方。此类型可以包含您想要的任何内容,例如从配置文件加载的键/值字典:

public class Configuration
{
    public string DriverName { get; set; }
    public string OtherSetting { get; set; }
}
最后,我们可以创建一个驱动程序。让我们创建一个
IPowerSupply

[DriverHandler(DriverType = typeof(IPowerSupply), ConfigurationName="BaseSupply")]
public class BasePowerSupply : IPowerSupply
{
    public BasePowerSupply(Configuration config) { /* ... */ }

    public void SetVoltage() { /* ... */ }

    public void SetCurrent() { /* ... */ }
}
重要的是,它用属性修饰,并且有一个构造函数(尽管我创建了工厂,以便它也可以使用默认构造函数):


依此类推。

我将使用以下代码:

public T GetDriver<T>(string name)
{
    return ((Func<string, T>)_factories[typeof(T)])(name);
}
var drivers = new Factory();
drivers.Define(s => new Foo(s));
drivers.Define(s => new Bar());
drivers.Define(s => new Baz());

var driver = drivers.Build<Foo>("foo");
基本上,
\u工厂
字典包含根据传入的字符串参数创建每个对象类型的所有代码。注意,在我上面的示例中,
Foo
类将
s
作为构造函数参数

public T GetDriver<T>(string name);
然后还可以在运行时修改字典,以满足您的需要,而无需重新编译代码


我甚至会更进一步。如果定义此factory类:

public class Factory
{
    private Dictionary<Type, Delegate> _factories = new Dictionary<Type, Delegate>();

    public T Build<T>(string name)
    {
        return ((Func<string, T>)_factories[typeof(T)])(name);
    }

    public void Define<T>(Func<string, T> create)
    {
        _factories.Add(typeof(T), create);
    }
}
公共类工厂
{
私有字典_factories=新字典();
公共T生成(字符串名称)
{
返回((Func)_工厂[类型(T)](名称);
}
公共无效定义(Func创建)
{
_Add(typeof(T),create);
}
}
然后,您可以编写以下代码:

public T GetDriver<T>(string name)
{
    return ((Func<string, T>)_factories[typeof(T)])(name);
}
var drivers = new Factory();
drivers.Define(s => new Foo(s));
drivers.Define(s => new Bar());
drivers.Define(s => new Baz());

var driver = drivers.Build<Foo>("foo");
var驱动程序=新工厂();
定义(s=>newfoo);
Define(s=>newbar());
Define(s=>newbaz());
var driver=drivers.Build(“foo”);

我更喜欢这样。它是强类型的,在运行时很容易定制。

短语“基本上,想法是有一个对象,基于配置文件构建”泄露了一个不幸的事实,即为了能够做到这一点,您将放弃至少某种程度的类型安全性。也许有人可以证明我的假设是错误的——我很想看到它。这个中心对象可能能够通过类型而不是名称来搜索驱动程序。因此,您将使用
GetDriver
(),而不是
GetDriver(字符串名称)
。Unity游戏引擎可以做这样的事情。泛型,
dynamic
会更好。。。取决于你真正关心的是什么…@Katana314它至少需要考虑一个名字或类似的概念,因为每个驱动程序可能不止一个。例如,我们的长椅有3个电源。看起来您正在寻找。例如,实现。为了避免
开关
,您可以为所有
T
对象创建一个通用接口或基础对象,并通过反射实例化它们。这将帮助您避免对
GetDriver
方法进行更改谢谢,这正是我想要的!我没有意识到泛型可以用在任何方法上,我认为它只适用于构造函数。这甚至不能编译。你不能打开类型,开关应该有花括号。老实说,我本来打算在“GetDriver”方法中强制转换。最终,调用此“DriverSource”的代码需要请求与底层配置一致的内容,或者需要存在异常(即,如果调用“var driver=GetDriver”(“万用表”),则必须抛出运行时异常)。但是有