如何确定对象的类型并将其作为参数传递给方法
本文关键字:参数传递 方法 对象 何确定 类型 | 更新日期: 2023-09-27 18:22:22
我的应用程序包含一个名为Statistic
的基类和从中继承的三个类:LSP
、CPU
、Memory
。我还有一个名为ExecuteRequest
的附加类,它的构造函数采用Statistic
的实例或更派生的类型之一(LSP
、CPU
或Memory
)。我想做的是:确定它是什么类型的对象(是LSP
、CPU
还是Memory
)。
为了实现这一点,我创建了DeterminateKpiType
方法,该方法将检查传入的Statistic
实例,并将其强制转换为该类型的特定属性。一旦完成,这个特定对象将被传递给RunRequest()
方法。不幸的是,我在尝试解决此问题时遇到了一个问题。
我收到错误(当调用DeterminateKpiType()
时),说它不能返回这些类型,并且我不知道如何将对象传递给RunRequest()
方法。我怎样才能达到这个结果?如果有什么不清楚的地方,请随意回复/询问。
以下是代码列表:
class ExecuteRequest
{
public Statistic KPI { get; set; }
public LSP LSP { get; set; }
public CPU CPU { get; set; }
public Memory Memory { get; set; }
public ExecuteRequest(Statistic kpi)
{
KPI = kpi;
specificStatisticKPI = DeterminateKpiType(KPI);
RunRequest(specificStatisticKPI)
}
public T DeterminateKpiType<T>(Statistic KPI)
{
if (KPI.GetType() == typeof(LSP))
{
LSP = KPI as LSP;
return LSP;
}
if (KPI.GetType() == typeof(CPU))
{
CPU = KPI as CPU;
return CPU;
}
if (KPI.GetType() == typeof(Memory))
{
Memory = KPI as Memory;
return Memory;
}
}
public void RunRequest(specificStatisticKPI what type ?????)
{
specificStatisticKPI.SomeMethod
}
}
我有一些理论我不知道它是否有帮助,但我很想告诉你,首先specificStatisticKPI
是什么类型的?如果它被设置为Statistic
类型,我认为你需要转换它,或者它不能包含Memory
、LSP
或CPU
,也就是说,第二,RunRequest()
方法应该能够接受三种类型的类,或者如果处理了这些事情,这些类可以隐式地相互转换。我认为你的代码应该可以工作。祝你好运
您所采取的方法存在一些挑战(我怀疑这些挑战会导致您面临的一些困惑),因此我将尝试概述这些挑战,并提供解决方案,使您获得所需的结果。
挑战1:
您在ExecuteRequest
类的构造函数中做了太多的逻辑。构造函数应该被限制为非常简单的条件检查(如果有的话),并且肯定不应该执行任何操作。在这里,你至少有两个选择:
- 将
ExecuteRequest
类重构为一个没有构造函数的静态类(根据当前代码,我看不出有什么理由让它成为可实例化类型)和一个接受Statistic
实例作为参数的静态方法(例如RunRequest
方法) - 将构造函数更改为仅初始化
Statistic
实例,并使使用ExecuteRequest
的代码调用RunRequest
特别注意构造函数(取自下面的MSDN链接):
不建议使用公共字段进行编程因为它允许程序中任何位置的任何方法不受限制,并且对对象内部工作的未经验证的访问。数据成员应通常是私有的,并且只能通过类访问方法和属性。
和
在构造函数中做最少的工作。建设者不应该做太多除了捕获构造函数参数之外的其他工作。任何其他处理应当被延迟直到需要为止。
以下是一些对构造函数有用的指南,以及如何最好地使用它们:
- http://msdn.microsoft.com/en-us/library/ms229060(v=vs.110).aspx
- http://msdn.microsoft.com/en-us/library/k6sa6h87(v=vs.110).aspx
- http://msdn.microsoft.com/en-us/library/ms229060(v=vs.100).aspx
挑战2:
使用泛型和条件类型逻辑通常是互斥的(其中一个选项比另一个更受欢迎),将两者结合起来通常是一种代码嗅觉。当使用泛型时,其中一个好处来自"泛型类型约束"的使用。这些约束允许您尽可能多地了解基类型的所有潜在传入实现,同时允许在不必修改代码的情况下创建新实例。这个想法本质上是一个利斯科夫替代。
有关泛型类型约束的详细信息,请参见:http://msdn.microsoft.com/en-us/library/d5x73970.aspx
以下是MSDN文档的摘录:
通过约束类型参数,可以增加允许的操作和方法调用约束类型及其继承层次结构中的所有类型。因此,当您设计泛型类或方法时,如果对泛型成员执行简单以外的任何操作赋值或调用System.Object不支持的任何方法将不得不对类型参数应用约束。
可能的解决方案
总是有很多方法可以解决这样的编程问题,这里有两种变体可以解决您面临的挑战。
注意:我在LinqPad中创建了这些类,所以它们都经过了工作测试(但您的实际类可能与我的不同)。
变体1(具有类范围泛型类型约束的可实例化ExecuteRequest
):
void Main() {
LSP lspStatistic = new LSP();
Memory memoryStatistic = new Memory();
CPU cpuStatistic = new CPU();
ExecuteRequest<CPU> cpuRequest = new ExecuteRequest<CPU>(cpuStatistic);
ExecuteRequest<LSP> lspRequest = new ExecuteRequest<LSP>(lspStatistic);
ExecuteRequest<Memory> memoryRequest = new ExecuteRequest<Memory>(memoryStatistic);
cpuRequest.RunRequest();
lspRequest.RunRequest();
memoryRequest.RunRequest();
}
public class ExecuteRequest<TStatistic> where TStatistic : Statistic {
private TStatistic _kpi; //Whichever type the class was created as. This enables us to have intellisense support for the specific generic type outside of this class if we need it.
//Hide the default constructor from the outside world (require a statistic)
private ExecuteRequest() : this(null) {
} // end default constructor
public ExecuteRequest(TStatistic kpi) {
_kpi = kpi;
} // end overloaded constructor
public void RunRequest() {
this.KPI.SomeMethod(); //Since we know that KPI will be AT LEAST a Statistic as specified by the generic type constraint, we can access the base class members here without having to figure out which type it is because we don't actually care what type it is, just that it is a Statistic
} // end method RunRequest
public TStatistic KPI {
get {
return _kpi;
} set {
_kpi = value;
}
} // end property KPI
} // end class ExecuteRequest
public abstract class Statistic {
protected Statistic() {
} // end default constructor
public abstract void SomeMethod();
} // end class Statistic
public class LSP : Statistic {
public LSP() : base() {
} // end default constructor
public override void SomeMethod() {
Debug.WriteLine("This is the LSP implementation of SomeMethod.");
} // end method SomeMethod
} // end class LSP
public class CPU : Statistic {
public CPU() : base() {
} // end default constructor
public override void SomeMethod() {
Debug.WriteLine("This is the CPU implementation of SomeMethod.");
} // end method SomeMethod
} // end class CPU
public class Memory : Statistic {
public Memory() : base() {
} // end default constructor
public override void SomeMethod() {
Debug.WriteLine("This is the Memory implementation of SomeMethod.");
} // end method SomeMethod
} // end class Memory
输出:
这是SomeMethod的CPU实现。
这是SomeMethod的LSP实现。
这是SomeMethod的Memory实现。
变体2(具有泛型类型参数和约束的静态ExecuteRequest
):
void Main() {
LSP lspStatistic = new LSP();
Memory memoryStatistic = new Memory();
CPU cpuStatistic = new CPU();
ExecuteRequest.RunRequest<LSP>(lspStatistic);
ExecuteRequest.RunRequest<Memory>(memoryStatistic);
ExecuteRequest.RunRequest<CPU>(cpuStatistic);
}
public static class ExecuteRequest {
public static void RunRequest<TStatistic>(TStatistic statInstance) where TStatistic : Statistic {
if(statInstance != null) {
statInstance.SomeMethod();
} // end if
} // end method RunRequest
} // end class ExecuteRequest
输出:
这是SomeMethod的LSP实现。
这是SomeMethod的Memory实现。
这是SomeMethod的CPU实现。
作为替代方案,由于使用静态实现,您不需要intellisense,因此可以省略泛型,如下所示:
void Main() {
LSP lspStatistic = new LSP();
Memory memoryStatistic = new Memory();
CPU cpuStatistic = new CPU();
ExecuteRequest.RunRequest(lspStatistic);
ExecuteRequest.RunRequest(memoryStatistic);
ExecuteRequest.RunRequest(cpuStatistic);
}
public static class ExecuteRequest {
public static void RunRequest(Statistic statInstance){
if(statInstance != null) {
statInstance.SomeMethod();
} // end if
} // end method RunRequest
} // end class ExecuteRequest
希望这能给你一些如何前进的指导。