字符串以()开头以任何方式避免两次检查
本文关键字:检查 两次 何方 开头 任何方 字符串 | 更新日期: 2023-09-27 18:27:01
我有这段代码。这在当时并不明显,但编写的代码总是会选择第一个选项,因为"fc"answers"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()以模式作为输入。我测试的字符串要么是模式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
}
}
我发现正则表达式很简单。以下是Regex.IsMatch:的示例
if (Regex.IsMatch(str, "^(?:fc|fcip)") {
...
}
^
表示"anchor to The start"(或"starts with"),|
表示"非此即彼",(?:...)
表示分组。
然而,既然每个匹配都调用两个不同的方法,为什么不让它保持原样呢?我删除了额外的代码,使其更易于查看。
正如康拉德所指出的,条件句的顺序很重要。
var command = BlockToProcess[0];
if (command.StartsWith("fcip")) {
this.ParseFCIPInterface(BlockToProcess); // ParseFCIP
} else if (command.StartsWith("fc") {
this.ParseFCInterface(BlockToProcess); // ParseFC
}
快乐的编码。
假设StartsWith("fcip")
暗示StartsWith("fc")
,只需先测试后者,然后嵌套第二个测试。
此外,您的try
块完全冗余,不起任何作用。
if (BlockToProcess[0].StartsWith(fcportdelimit) {
if (BlockToProcess[0].StartsWith(fcipportdelimit) {
// do something here
}
else {
// do something here
}
}
(当然,第二次检查仍然包含一个冗余部分,因为它再次检查fc
,但重构此检查只会降低代码的可读性,不一定有利于性能。)
进行两次比较没有错,比如:
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
}
}
只需将其更改为:
if (BlockToProcess[0].StartsWith(fcipportdelimit))
{
}
else if (BlockToProcess[0].StartsWith(fcportdelimit))
{
}
至少你会得到一些有用的东西。效率在这里似乎不是一个问题。
怎么样?
BlockToProcess[0].StartsWith(fcportdelimit) || BlockToProcess[0].StartsWith(fcipportdelimit)
我测试的字符串要么是模式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;
}
这个答案可能有些过头了,但应该会产生一个更易于维护的&可测试的解决方案。它还需要一些相当先进的测试&重构以保持现有行为。
这里的总体思想是,您提供的代码意味着单个解析类可能对单个操作了解太多。考虑到这一点,我最初会创建一个具有两个实现的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
检查,你可以添加一个像这样的空对象实现(并确保工厂接受它):
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"; } }
}
按相反的顺序执行,首先检查fcipportdelimite,然后检查else块中的fcportdelimite。这将解决您的问题
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;
}
}