使用反射获取 class 中使用的常量
Getting used constants in a class with reflection
所以...请看这个例子:
public class StatesList() {
public const string State1Name = "State1";
public const string State2Name = "State2";
public const string State3Name = "State3";
}
public class Test() {
private currentState = StatesList.State1Name;
public static void Main(string[] args) {
while(true) {
if(currentState == StatesList.State1Name) {
State1();
} else if (currentState == StatesList.State3Name) {
State2();
}
}
}
public void ChangeState(string newState) {
currentState = newState;
}
public void State1() {
// do stuff.
if(iAmSilly) {
ChangeState(StatesList.State3Name);
}
}
public void State2() {
// do stuff.
if(!iAmSilly) {
ChangeState(StatesList.State1Name);
}
}
}
我想要实现的是能够 "parse" 测试 class 并创建一个包含所用状态名称的列表。在示例中,我希望能够创建一个包含 StatesList.State1Name 和 StatesList.State3Name 的列表。是否可以使用反射来实现它,或者我实际上是否必须创建一个解析器(将 cs 文件作为文本加载)来实现它?
非常感谢:-)
反射是不可能的。无法通过反射获得源代码;只有元数据。常量在编译后被替换为它们的字面值,所以即使你查看 class 的 IL,你也无法判断是否使用了常量或字面量字符串。
解析源代码可能是您的最佳选择。
使用正则表达式并解析文件:
private static List<string> GetUsedConstants(string path_to_file, string const_class)
{
var text = File.ReadAllText(path_to_file);
var rx = new Regex(const_class + @"\.\w+");
return rx.Matches(text).Cast<Match>().Select(m => m.Value).Distinct().ToList();
}
正如我在评论中提到的,您似乎通过尝试实现 "State Machine"。这并不能直接回答您的问题,但可以帮助您解决实际问题。状态被实现为真实状态 class 的实际子classes。这样你就不需要任何 if
或 case
语句来找出哪个状态的逻辑 运行;每个 subclass 都有一个 Execute 方法,它有自己的状态特定逻辑。如果这听起来像你感兴趣的东西,请告诉我,我会为你做一个简单的例子。
控制台应用程序中状态机的一个非常简单的示例。它在 2 个状态之间切换,其中一个状态从 1 计数到 5,第二个状态从 1 计数到 10。
using System;
namespace StateMachineExample
{
class Program
{
static void Main(string[] args)
{
SimpleStateMachine sm = new SimpleStateMachine();
sm.ChangeState(new State1(sm));
sm.Run();
}
}
class SimpleStateMachine
{
private State _currentState;
public void Run()
{
while (true)
{
_currentState.Execute();
}
}
public void ChangeState(State newState)
{
Console.WriteLine($"Changing state to: {newState.GetType()}");
_currentState = newState;
}
}
abstract class State
{
public State(SimpleStateMachine sm)
{
StateMachine = sm;
}
protected SimpleStateMachine StateMachine { get; }
public abstract void Execute();
}
class State1 : State
{
public State1(SimpleStateMachine sm) : base(sm) { }
private int _num = 0;
public override void Execute()
{
_num = _num + 1;
Console.WriteLine(_num);
if (_num > 10)
{
StateMachine.ChangeState(new State2(StateMachine));
}
}
}
class State2 : State
{
public State2(SimpleStateMachine sm) : base(sm) { }
private int _num = 0;
public override void Execute()
{
_num = _num + 1;
Console.WriteLine(_num);
if (_num > 5)
{
StateMachine.ChangeState(new State1(StateMachine));
}
}
}
}
所以...请看这个例子:
public class StatesList() {
public const string State1Name = "State1";
public const string State2Name = "State2";
public const string State3Name = "State3";
}
public class Test() {
private currentState = StatesList.State1Name;
public static void Main(string[] args) {
while(true) {
if(currentState == StatesList.State1Name) {
State1();
} else if (currentState == StatesList.State3Name) {
State2();
}
}
}
public void ChangeState(string newState) {
currentState = newState;
}
public void State1() {
// do stuff.
if(iAmSilly) {
ChangeState(StatesList.State3Name);
}
}
public void State2() {
// do stuff.
if(!iAmSilly) {
ChangeState(StatesList.State1Name);
}
}
}
我想要实现的是能够 "parse" 测试 class 并创建一个包含所用状态名称的列表。在示例中,我希望能够创建一个包含 StatesList.State1Name 和 StatesList.State3Name 的列表。是否可以使用反射来实现它,或者我实际上是否必须创建一个解析器(将 cs 文件作为文本加载)来实现它?
非常感谢:-)
反射是不可能的。无法通过反射获得源代码;只有元数据。常量在编译后被替换为它们的字面值,所以即使你查看 class 的 IL,你也无法判断是否使用了常量或字面量字符串。
解析源代码可能是您的最佳选择。
使用正则表达式并解析文件:
private static List<string> GetUsedConstants(string path_to_file, string const_class)
{
var text = File.ReadAllText(path_to_file);
var rx = new Regex(const_class + @"\.\w+");
return rx.Matches(text).Cast<Match>().Select(m => m.Value).Distinct().ToList();
}
正如我在评论中提到的,您似乎通过尝试实现 "State Machine"。这并不能直接回答您的问题,但可以帮助您解决实际问题。状态被实现为真实状态 class 的实际子classes。这样你就不需要任何 if
或 case
语句来找出哪个状态的逻辑 运行;每个 subclass 都有一个 Execute 方法,它有自己的状态特定逻辑。如果这听起来像你感兴趣的东西,请告诉我,我会为你做一个简单的例子。
控制台应用程序中状态机的一个非常简单的示例。它在 2 个状态之间切换,其中一个状态从 1 计数到 5,第二个状态从 1 计数到 10。
using System;
namespace StateMachineExample
{
class Program
{
static void Main(string[] args)
{
SimpleStateMachine sm = new SimpleStateMachine();
sm.ChangeState(new State1(sm));
sm.Run();
}
}
class SimpleStateMachine
{
private State _currentState;
public void Run()
{
while (true)
{
_currentState.Execute();
}
}
public void ChangeState(State newState)
{
Console.WriteLine($"Changing state to: {newState.GetType()}");
_currentState = newState;
}
}
abstract class State
{
public State(SimpleStateMachine sm)
{
StateMachine = sm;
}
protected SimpleStateMachine StateMachine { get; }
public abstract void Execute();
}
class State1 : State
{
public State1(SimpleStateMachine sm) : base(sm) { }
private int _num = 0;
public override void Execute()
{
_num = _num + 1;
Console.WriteLine(_num);
if (_num > 10)
{
StateMachine.ChangeState(new State2(StateMachine));
}
}
}
class State2 : State
{
public State2(SimpleStateMachine sm) : base(sm) { }
private int _num = 0;
public override void Execute()
{
_num = _num + 1;
Console.WriteLine(_num);
if (_num > 5)
{
StateMachine.ChangeState(new State1(StateMachine));
}
}
}
}