String StartsWith()任何方法避免2次检查?

时间:2012-03-06 17:55:32

标签: c#

我有这个代码。当时并不明显,但所写的代码总是会选择第一个选项,因为“fc”和“fcip”都以“fc”开头。

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
    }
}

8 个答案:

答案 0 :(得分:7)

我发现正则表达式很容易。以下是Regex.IsMatch的示例:

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

^说“锚定到开头”(或“以”开头“),|说”是 - 或“,(?:...)用于分组。< / p>

但是,由于每个匹配调用两个不同的方法,为什么不把它留下来呢?我删除了额外的代码,以便更容易看到。

正如Konrad指出的那样,条件的顺序非常重要。

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

快乐的编码。

答案 1 :(得分:6)

鉴于StartsWith("fcip") 暗示 StartsWith("fc"),只需先测试后者并嵌套第二次测试。

此外,您的try完全多余,并且不起作用。

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

(当然,第二次检查仍然包含一个冗余部分,因为它再次检查fc但重构此检查只会使代码的可读性降低,并不一定会使性能受益。)

答案 2 :(得分: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
    }
}

答案 3 :(得分:1)

只需将其更改为:

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

至少你会有一些有用的东西。效率在这里似乎不是问题。

答案 4 :(得分:0)

怎么样?

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

答案 5 :(得分: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;
} 

答案 6 :(得分: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 { ... }

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

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检查,你可以像这样添加一个Null Object实现(并确保工厂选择它):

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"; } }
}

答案 7 :(得分: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;
                            } 
                        }