目前正在C#中进行大学项目,其中包括将一种代码形式转换为另一种形式的代码,其中涉及从许多可用方法中选择适当的方法/功能。这里的问题是,使用任何模式匹配技术实现它,而不是使用许多IF ELSE语句。
目前我已经使用嵌套的IF ELSE语句实现了这一点,这些语句填充整个程序,并在完成时看起来像幼稚的代码。
当前实施: -
输入:
//stored in list<string>
get(3 int) //type1
get(int:a,b,c) //type2
get(name) //type3
//list passed to ProcessGET method
使用if else:
public string ProcessGET(List<string> inputData)
{
foreach(var item in inputData)
{
if (inputData.item.Split('(')[1].Split(')')[0].Contains(':'))
{
return Type2 result;
}
else if (!inputData.item.Split('(')[1].Split(')')[0].Contains(':') && Convert.ToInt32(inputData.item.Split('(')[1].Split(')')[0].Split(' ')[0])>0)
{
return Type1 result;
}
else
{
return Type3 result;
}
}
}
我想要的是这样的,
/stored in list<string>
get(3 int) //type1
get(int:a,b,c) //type2
get(name) //type3
//list passed to ProcessGET method
public string ProcessGET(List<string> inputData)
{
foreach(var itm in inputData)
{
// call appropriate method(itm) based on type using some pattern matching techniques
}
}
string Method1(var data)
{
return result for type1;
}
string Method2(var data)
{
return result for type2;
}
string Method3(var data)
{
return result for type3;
}
通常我的程序主要为各种类型的输入关键字做这种工作,比如'get','output','declare'等等......其中Get转换为Scanf语句,输出到printf语句等等上。 在这种情况下,如果我使用IF ELSE,我的项目充满了If else语句。
当我刚开始学习C#时,我不知道这样的事情是否存在(谷歌搜索但是没有找到我想要的东西),所以关于这个问题的任何帮助都将非常有帮助(使用)发展。
非常感谢提前。
答案 0 :(得分:3)
解决此问题的另一种方法是引入一个界面,比如IMatcher
。该接口有一个方法Match
,它返回您的类型或完全转换的行。
您创建了多个实现IMatcher
的类。
然后您的主循环变为:
var matchers = new [] { new MatcherA(), new MatcherB(), ... };
foreach (string line in input)
foreach (matcher in matchers)
{
var match = matcher.Match(line);
if (match != null) return match;
}
没有更大的if声明。每个匹配器都有自己的小类,您可以为每个匹配器编写单元测试。此外,使用RegEx可以使您的匹配器更简单。
答案 1 :(得分:1)
我会在这里留下一些你可以看一下的建议。这是一些基本代码。
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace TestStuff
{
class Program
{
//Input string should be of the form "<type>:<index>"
static dynamic GiveMeSomethingDynamic(string someInput)
{
/* predefined arrays sothat we can return something */
string[] _storedStrings = { "Word 1", "word 2", "word 3" };
int[] _storedInts = { 1, 2, 3 };
float[] _storedFloats = { 3.14f, 2.71f, 42.123f };
/* Parse the input command (stringly typed functions are bad, I know.) */
string[] splitted = someInput.Split(':');
string wantedType = splitted[0];
int index = int.Parse(splitted[1]);
/* Decide what to return base on that argument */
switch (wantedType)
{
case "int":
return _storedInts[index];
case "string":
return _storedStrings[index];
case "float":
return _storedFloats[index];
//Nothing matched? return null
default:
return null;
}
}
static void Main(string[] args)
{
/* get some return values */
dynamic firstOutput = GiveMeSomethingDynamic("string:0");
dynamic secondOutput = GiveMeSomethingDynamic("int:1");
dynamic thirdOutput = GiveMeSomethingDynamic("float:2");
/* Display the returned objects and their type using reflection */
Console.WriteLine("Displaying returned objects.\n" +
"Object 1: {0}\t(Type: {1})\n" +
"Object 2: {2}\t\t(Type: {3})\n" +
"Object 3: {4}\t\t(Type: {5})\n",
firstOutput, firstOutput.GetType(),
secondOutput, secondOutput.GetType(),
thirdOutput, thirdOutput.GetType());
/* Act on the type of a object. This works for *all* C# objects, not just dynamic ones. */
if (firstOutput is string)
{
//This was a string! Give it to a method which needs a string
var firstOutputString = firstOutput as string; //Cast it. the "as" casting returns null if it couldn't be casted.
Console.WriteLine("Detected string output.");
Console.WriteLine(firstOutputString.Substring(0, 4));
}
//Another test with reflection.
Console.WriteLine();
//The list of objects we want to do something with
string[] values = { "string:abcdef", "int:12", "float:3.14" };
foreach(var value in values)
{
/* Parse the type */
string[] parsed = value.Split(':');
string _type = parsed[0];
string _argument = parsed[1];
switch (_type)
{
case "string":
//This is a string.
string _stringArgument = _argument as string;
Method1(_stringArgument);
break;
case "int":
//Do something with this int
int _intArgument = int.Parse(_argument);
Method2(_intArgument);
break;
case "float":
float _floatArgument = float.Parse(_argument);
Method3(_floatArgument);
break;
default:
Console.WriteLine("Unrecognized value type \"{0}\"!", _type);
break;
}
}
Console.ReadLine();
}
public static void Method1(string s) => Console.WriteLine("String Function called with argument \"{0}\"", s);
public static void Method2(int i) => Console.WriteLine("int Function called with argument {0}", i);
public static void Method3(float f) => Console.WriteLine("float Function called with argument {0}", f);
}
}
函数GiveMeSomethingDynamic()
给出的第一种方法依赖于dynamic
关键字,它可以返回任意类型。根据输入字符串,它可以返回string
,int
或float
。在Main()
函数中调用该方法,并且例如使用例如方法检查返回对象的类型。 firstOutput is string
(is
运算符). It could have also been done with
if(firstOutput.GetType()== typeof(string))`。
第二种方法是经典的“解析和演员”技巧。我们解析格式为<type>:<value>
的输入字符串,然后使用转换或解析的参数调用不同的函数。这可能是你想要的。
还有一种“hacky”方式赋予函数任意类型。在那里,您可以在输入参数上使用dynamic
关键字,如
public dynamic superDynamic(dynamic inputVar)
{
//Figure out the type of that object
//return something dynamic
}
“oldschool”方法(不使用dynamic
)只会将object
类型传递给每个函数,但解析是等效的(if(someArgument.GetType() == typeof(string))
...)。
希望这能为您提供一些关于如何解析这些字符串,将它们转换为不同类型并使用它调用不同函数的想法。
答案 2 :(得分:1)
所以类型作为字符串存储在列表中,对吧?你想根据字符串的值调用不同的函数吗?
以下是我完成代码的方式:
创建界面:
public interface IMyType
{
string Result();
string Input {get; set;}
}
以及实现它的三个类:
public class Type1 : IMyType
{
public string Result()
{
// do something
}
public string Input {get; set;}
}
(重复Type2和Type3)
3.然后创建一个返回这三种类型之一的方法 基于匹配字符串输入的模式
public IMyType GetAppropriateType(string input)
{
if (inputData.item.Split('(')[1].Split(')')[0].Contains(':'))
{
return new Type2 {Input = input};
}
//etc
}
public string ProcessGET(List<string> inputData)
{
foreach(var itm in inputData)
{
IMyType type = GetAppropriateType(itm);
type.Result();
}
}
也可能值得查看字符串匹配的正则表达式