0

我想解析一个包含几十个条目的文本文件。现在,我有一个简单的解决方案,可以逐行读取并与硬编码字符串进行比较:

while ((line = reader.ReadLine()) != null) //returns null if end of stream
{
    cmpStr = "MODE";
    try
    {
        if (line.Equals(cmpStr))                        
            GlobalData.mode = Convert.ToInt32(line.Remove(0, cmpStr.Length));
    }
    catch { }

    cmpStr = "TIME_YEAR";
    try
    {
        if (line.Equals(cmpStr))                        
            GlobalData.time_year = Convert.ToInt32(line.Remove(0, cmpStr.Length));
    }
    catch { }


    // ... repeat to parse the remaining lines
}

GlobalData 是一个静态类,如下所示:

public static class GlobalData
{

    public static int mode;                 
    public static int time_year;
    public static int time_month;
    public static int time_day;
    public static int time_hour;
    public static int time_minute;
    // other entries omitted

    public static string[] GlobalKeywords = new  string[37] 
    {
        "MODE", 
        "TIME_YEAR",
        "TIME_MONTH",
        "TIME_DAY",
        "TIME_HOUR",
        "TIME_MINUTE",
        // other entries omitted      
    };
}

如果可以通过 index访问我的静态字段,我会这样做:

int i = 0;
while ((line = reader.ReadLine()) != null) 
{
    cmpStr = GlobalData.GlobalKeywords[i];    // when i == 0: cmpStr = "MODE"

    if (line.Equals(cmpStr))
        GlobalData[i] = Convert.ToInt32(line.Remove(0, cmpStr.Length));
        // GlobalData[0] would be GlobalData.mode, and so on (but doesn't work)

    i++;
}
catch { }

因此,即使我可以设置一个循环来与关键字字符串数组进行比较,我如何分配静态类的某个字段?

克里斯

4

5 回答 5

1

替换这个:

public static int mode;                 
public static int time_year;
public static int time_month;
public static int time_day;
public static int time_hour;
public static int time_minute;

有了这个:

public static Dictionary<string, int> my_values = new Dictionary<string, int>();

然后替换:

GlobalData[i] = Convert.ToInt32(line.Remove(0, cmpStr.Length));

和:

GlobalData.my_values[cmpStr] = Convert.ToInt32(line.Remove(0, cmpStr.Length));

即使我不明白你期望它如何Convert.ToInt32工作,那也应该做你想做的事。您调用的方式Remove将创建一个空字符串(可能会转换为 0,我不记得了),即使没有,该行也不包含数字,因为您成功地将它与“MODE”之类的字符串进行了比较”。

于 2013-10-25T11:49:12.343 回答
1

一种简单(但不是很干净)的方法是将索引器添加到全局数据类中,并根据索引决定要设置的字段。但是每次添加字段时都必须扩展索引器(基本上是将 if/switch 从 while 循环移动到索引器中)。
如果您可以将关键字与字段名称匹配,您也可以使用反射。这不是很高效,但不需要扩展,只要您可以将关键字映射到新字段名称即可。
另一种方法是创建字典>。在这本词典中,您注册了关键字,例如(伪代码): 类级别变量:

private keywordsDict = new Dictionary<string, Action<int>>();

在构造函数中:

keywordsDict.Add("MODE", delegate(value) GlobalData.mode = value);

在while循环中:

var action = keywordsDict[line];
action(value);

在后一种方法中,如果您有一个新的关键字/字段,您只需要扩展字典而不是算法本身。

于 2013-10-25T11:55:21.197 回答
1

解决问题的一种优雅方法是为每个可接受的字符串准备不同的操作。您使用Dictionary(Of String, <Action>)where Action 是一种常见的委托类型,它在输入中接收字符串并知道如何根据行首出现的关键字相应地处理它。

// The common signature for every methods stored in the value part of the dictionary
public delegate void ParseLine(string line);

// Global dictionary where you store the strings as keyword
// and the ParseLine as the delegate to execute
Dictionary<String, ParseLine> m_Actions = new Dictionary<String, ParseLine>() ;

void Main()
{
    // Initialize the dictionary with the delegate corresponding to the strings keys
    m_Actions.Add("MODE", new ParseLine(Task1));
    m_Actions.Add("TIME_YEAR", new ParseLine(Task2));
    m_Actions.Add("TIME_MONTH", new ParseLine(Task3));
    m_Actions.Add("TIME_DAY", new ParseLine(Task4));
    .....

    while ((line = reader.ReadLine()) != null) 
    {
        // Search the space that divide the keyword from the value on the same line
        string command = line.Substring(0, line.IndexOf(' ')).Trim();
        // a bit of error checking here is required
        if(m_Actions.ContainsKey(command))
            m_Actions[command](line);

    }
}

void Task1(string line)
{
    // this will handle the MODE line
    GlobalData.Mode = Convert.ToInt32(line.Substring(line.IndexOf(' ')+1).Trim());

}
void Task2(string line)
{
     GlobalData.time_year = Convert.ToInt32(line.Substring(line.IndexOf(' ')+1).Trim());
}
void Task3(string line)
{
    .....
}
void Task4(string line)
{
    .....
}
于 2013-10-25T11:57:19.283 回答
1

我不确定您的业务限制是什么,因此很难提出一个万无一失的解决方案,尽管有几点:

cmpStr = "MODE";
try
{
   if (line.Equals(cmpStr))                        
      GlobalData.mode = Convert.ToInt32(line.Remove(0, cmpStr.Length));
}

这不会像您(可能期望)那样工作 - 如果line.Equals("MODE")thenline.Remove(0, "MODE".Length)是一个空字符串。您可能想要的是line.StartsWith(cmpStr)or line.Contains(cmpStr)

GlobalData 是一个静态类

对于您正在做的事情,这似乎不是一个好方法。您可能想阅读静态类以及何时使用它们(MSDN 是一个很好的起点,尽管它显然不能涵盖所有内容:http: //msdn.microsoft.com/en-us/library/79b3xss3%28v =vs.80%29.aspx)。

除此之外,您可能可以简单地用字典替换所有 int 字段(尽管请重新考虑如上所述的静态方法):

public static Dictionary<String, int> Items = new Dictionary<String, int>();

然后您的解析代码可能如下所示:

while ((line = reader.ReadLine()) != null) //returns null if end of stream
{
   var matchingString
      = GlobalData.GlobalKeywords.FirstOrDefault(s => line.StartsWith(s));
   if (matchingString != null)
      GlobalData[matchingString]
           = Convert.ToInt32(line.Remove(0, matchingString.Length));
}

然后,您将能够使用 eg 获取该数据GlobalData.Items["MODE"]

最后一点:您可以考虑在全局数据类中引入常量值,例如:

public const String MODE = "MODE";

然后你可以使用GlobalData.Items[GlobalData.MODE]并避免拼写错误:写作GlobalData.Items[GlobalData.MODe]会导致编译错误。

于 2013-10-25T12:03:10.503 回答
0

也许我可以告诉你如何在 C# 中实现它 (GlobalData[i]) 认为它不是你正在寻找的答案。

    class GlobalData
    {
        private string[] array = new string[10];
        public GlobalData()
        {
           //now initialize array
           array[0] = "SomeThingA";
           array[1] = "SomeThingB";//continue initialization.
        }
        public string this[int index]
        {
            get {return array[index];}
        }
    }

现在客户可以使用 GlobalData 像,

    GlobalData gd = new GlobalData();
    gd[1] = "SomeOtherThing" ; //set the value.
    string value = gd[1];//get the value

但这不能通过将类设为静态来完成,因为您看到它与“this”一起使用

于 2013-10-25T12:33:50.200 回答