2012-03-06 56 views
2

我有这段代码。当时并不明显,但由于“fc”和“fcip”都以“fc”开头,因此写入的代码总是会选择第一个选项。String StartsWith()任何避免2次检查的方法?

string fcportdelimit = "fc"; 
string fcipportdelimit = "fcip"; 

if (BlockToProcess[0].StartsWith(fcportdelimit)) 
{ 
    try 
    { 
     this.ParseFCInterface(BlockToProcess); 
    } 
    catch (Exception E) 
    { 
     throw; 
    } 
} 
else if (BlockToProcess[0].StartsWith(fcipportdelimit)) 
{ 
    try 
    { 
     this.ParseFCIPInterface(BlockToProcess); 
    } 
    catch (Exception E) 
    { 
     throw; 
    } 
} 

我查看了字符串类,但没有看到将模式作为输入的StartsWith()或Contains()。我正在测试的字符串要么是一个patttern fcN/N,要么是fcipN,其中N是一个数字。所以,我想我必须做这样的事情?

if (BlockToProcess[0].StartsWith(fcportdelimit || fcipportdelimit) 
{ 
    if (BlockToProcess[0].StartsWith(fcipportdelimit) 
    { 
     // do something here 
    } 
    else 
    { 
     //since fcipportdelimit didn't match it must be an fcport 
     //so do something else 
    } 
} 
+0

'StartsWith(fcportdelimit || fcipportdelimit)'是有效的语法很远...... – 2012-03-06 17:57:17

+0

听起来像是正是这类问题该正则表达式的是。也许看看他们。 – 2012-03-06 17:59:10

+0

你考虑过正则表达式匹配吗? – Brettski 2012-03-06 17:59:42

回答

6

鉴于StartsWith("fcip")意味着StartsWith("fc"),只是先测试后者,并嵌套第二个测试。

此外,您的try块是完全冗余和不起作用。

if (BlockToProcess[0].StartsWith(fcportdelimit) { 
    if (BlockToProcess[0].StartsWith(fcipportdelimit) { 
     // do something here 
    } 
    else { 
     // do something here 
    } 
} 

(当然,第二次检查仍含有多余的部分,因为它会检查fc再次重构,但该检查只是使代码的可读性变差并不见得会受益的性能。)

+0

这是我采取的方法。我不想这么轻易放弃 - 我认为可能有一种字符串的方法,我不知道它会做我想要的。 – 2012-03-06 19:44:06

7

我觉得正则表达式很容易。下面是Regex.IsMatch一个例子:

if (Regex.IsMatch(str, "^(?:fc|fcip)") { 
    ... 
} 

^说“锚到开始”(或,“打头”),则|说“非此即彼”,并且(?:...)为分组。

但是,由于每个匹配调用两种不同的方法,为什么不让它像它一样呢?我已经删除了额外的代码,使其更易于查看。

Konrad指出,条件的订单是重要的。

var command = BlockToProcess[0]; 
if (command.StartsWith("fcip")) { 
    this.ParseFCIPInterface(BlockToProcess); // ParseFCIP 
} else if (command.StartsWith("fc") { 
    this.ParseFCInterface(BlockToProcess); // ParseFC 
} 

快乐编码。

+1

但是,你仍然*需要确定哪些匹配(你*可以*使用正则表达式,但你的代码没有说明这一点)。而你的第二个代码不会*使用第二个分支 - 你需要反转条件。 – 2012-03-06 18:02:43

+0

@KonradRudolph的确,我错过了:更新的回应。 – 2012-03-06 18:03:18

+0

为什么在正则表达式中使用非捕获组?捕获组在这里没有用于任何东西,所以如果你把它们放在正则表达式中并不重要。 – svick 2012-03-06 18:05:45

0

怎么样?

BlockToProcess[0].StartsWith(fcportdelimit) || BlockToProcess[0].StartsWith(fcipportdelimit) 
1

有什么不妥做两个比较,像这样的:

if (BlockToProcess[0].StartsWith(fcportdelimit) 
    || BlockToProcess[0].StartsWith(fcipportdelimit)) 
{ 
    if (BlockToProcess[0].StartsWith(fcipportdelimit) 
    { 
    // do something here 
    } 
    else 
    { //since fcipportdelimit didn't match it must be an fcport 
     //so do something else 
    } 
} 
1

只需将其更改为:

if (BlockToProcess[0].StartsWith(fcipportdelimit)) 
{ 
} 
else if (BlockToProcess[0].StartsWith(fcportdelimit)) 
{ 
} 

和至少你有一些作品。效率在这里似乎不成问题。

0

我对测试字符串是否将是一个patttern FCN/N 或fcipN

所以,从逻辑上,你只需要进行一个测试。如果不以“FCIP”开始,那么它必须只是开始“FC”

string fcipportdelimit = "fcip"; 
try 
{ 
    if (BlockToProcess[0].StartsWith(fcipportdelimit)) 
    { 
     this.ParseFCIPInterface(BlockToProcess); 
    } 
    else 
    { 
     this.ParseFCInterface(BlockToProcess); 
    } 
} 
catch (Exception E) 
{ 
    throw; 
} 
0

这个答案很可能矫枉过正,但应该产生一个更易于维护的&检验的解决方案。它还需要一些相当先进的重构测试来保持现有的行为。

这里的一般想法是,您提供的代码意味着单个解析类可能对各个操作知之甚多。鉴于此,我最初将创建一个IParser接口两个实现。

public interface IParser 
{ 
    void Parse(string input); 
    string RequiredPrefix { get; } 

    /* you'll want to add anything that's appropriate for your code here */ 
} 

public class FcPortParser : IParser { ... } 
public class FcipPortParser : IParser { ... } 

然后创建一个工厂,返回相应的解析器给定的输入:

public class ParserFactory 
{ 
    private List<IParser> _knownParsers; 

    public ParserFactory() 
    { 
     // you should be able to initialize this dynamically but that's off-topic here 
     _knownParsers = new List<IParser> { new FcPortParser(), new FcipPortParser() }; 
    } 

    public IParser GetFromString(string given) 
    { 
     // return the IParser with the longest prefix that given starts with 
     // this will return null for a non-match 
     return _knownParsers.Where(p => given.StartsWith(p.RequiredPrefix)) 
          .OrderByDescending(p => p.RequiredPrefix.Length) 
          .FirstOrDefault(); 
    } 
} 

有了这个解决方案,您可以轻松地测试各个分析器以及工厂返回一个合适的。

//NUnit 
Assert.IsInstanceOf<FcipPortParser>(factory.GetFromString("fcip...")); 
Assert.IsInstanceOf<FcPortParser>(factory.GetFromString("fc...")); 
Assert.IsNull(factory.GetFromString("undefined...")); 

...现在你的代码变得这样:

var parser = _factory.GetFromString(BlockToProcess[0]); 
if (parser != null) 
{ 
    parser.Parse(BlockToProcess[0]); 
} 

如果你想避免parser != null检查,您可以添加像这样的一个空对象实现(并确保出厂精选它):

public class NullParser : IParser 
{ 
    public void Parse(string given) { /* do nothing */ } 
    // should return true for every non-null string 
    public string RequiredPrefix { get { return string.Empty; } } 
} 

现在,当您需要添加功能,你只需要添加一个新的IParser类(和,如果工厂没有动态初始化,工厂)。

public class FcNewParser : IParser 
{ 
    public void Parse(string given) { ... } 
    public string RequiredPrefix { get { return "fcnew"; } } 
} 
0

按照相反顺序执行,首先检查fcipportdelimit,然后检查else块中的fcportdelimit。这将解决您的问题

string fcportdelimit = "fc"; 
string fcipportdelimit = "fcip"; 

if (BlockToProcess[0].StartsWith(fcipportdelimit)) 
         { 
          try 
          { 
           this.ParseFCInterface(BlockToProcess); 
          } 
          catch (Exception E) 
          { 
           throw; 
          } 
         } 
         else if (BlockToProcess[0].StartsWith(fcportdelimit)) 
         { 
          try 
          { 
           this.ParseFCIPInterface(BlockToProcess); 
          } 
          catch (Exception E) 
          { 
           throw; 
          } 
         }