C# 以编程方式更改代码文件
我正在将我们的Web服务更改为异步模型。为此,我必须改变上百种方法 手动操作是一个没有吸引力的选择。是否无法以编程方式解析和更改多个函数/代码文件 例如:C# 以编程方式更改代码文件,c#,.net,code-generation,C#,.net,Code Generation,我正在将我们的Web服务更改为异步模型。为此,我必须改变上百种方法 手动操作是一个没有吸引力的选择。是否无法以编程方式解析和更改多个函数/代码文件 例如: [Webmethod] public void MyWebservice (string parameter1, string parameter2, string parameter3) { //Logic here } 并将此更改为: public void InternalMyWebservice (string paramete
[Webmethod]
public void MyWebservice (string parameter1, string parameter2, string parameter3)
{
//Logic here
}
并将此更改为:
public void InternalMyWebservice (string parameter1, string parameter2, string parameter3, AsyncCallback callback)
{
//Logic here
}
[Webmethod]
public void BeginMyWebservice (string parameter1, string parameter2, string parameter3, AsyncCallback callback, object asyncState)
{
//Queue InternalMyWebservice in a threadpool
}
public void EndMyWebservice(IAsyncResult asyncResult)
{
//Set return values
}
对于每个Web服务,我必须做的事情基本相同。将名称更改为InternalX,添加一个参数并创建begin&end方法。尝试通过Resharper找到解决方案,如果不使用Regex替换一些文本。尝试通过Resharper找到解决方案,如果不使用Regex替换一些文本。我实际上对.NET框架不太熟悉,但这肯定可以通过正则表达式来实现。我实际上对.NET framework不太熟悉,但这肯定可以通过正则表达式来实现。为什么不只编写一个包装类,哪一个将在构造时获取现有类或委托的对象,并异步调用所需的方法?现有类的方法仍然可以是同步的。为什么不编写一个包装类,它将在构造时获取现有类或委托的对象,并异步调用所需的方法?现有类的方法仍然可以是同步的。您应该能够使用CSharpCodeProvider.Parse方法生成CodeCompileUnit实例,该实例是代码的面向对象表示形式。有了它,你可以深入到你的方法,改变参数,添加新的方法和东西,当你完成后,你可以把代码保存回一个文本文件。通过调用CodeDomProvider.GenerateCodeCodeFromCompileUnit并传递修改后的CodeCompileUnit来生成代码
您应该能够使用CSharpCodeProvider.Parse方法生成CodeCompileUnit实例,它是代码的面向对象表示形式。有了它,你可以深入到你的方法,改变参数,添加新的方法和东西,当你完成后,你可以把代码保存回一个文本文件。通过调用CodeDomProvider.GenerateCodeCodeFromCompileUnit并传递修改后的CodeCompileUnit来生成代码
您可以使用类似的解析器生成器。为只解析类和方法声明而忽略方法代码的C子集编写ANTLR语法应该不难。或者您可以使用ANTLR站点上的一个C语法 ANTLR有一个称为重写语法的功能,例如,外观非常接近您想要做的事情 但就个人而言,我不会将生成的方法与实际方法放在一个文件中。如果您在生成的代码中发现一个bug并希望重新生成它们,那么解析器会变得更复杂,因为它必须识别以前生成的方法。编辑生成的方法的诱惑非常大。此外,这似乎违反了单一责任原则,但这可能是一个品味问题
我会将生成的方法放在一个单独的文件(派生类或部分类声明)中。这样做的好处是您不需要解析器:如果未生成的类文件可能使用抽象或部分方法声明进行编译,那么您可以编译它,只需使用众所周知的反射机制即可获得所需的所有信息。您所需要的只是一个模板框架(如or)来生成代码。您可以使用解析器生成器(如。为只解析类和方法声明而忽略方法代码的C子集编写ANTLR语法应该不难。或者您可以使用ANTLR站点上的一个C语法 ANTLR有一个称为重写语法的功能,例如,外观非常接近您想要做的事情 但就个人而言,我不会将生成的方法与实际方法放在一个文件中。如果您在生成的代码中发现一个bug并希望重新生成它们,那么解析器会变得更复杂,因为它必须识别以前生成的方法。编辑生成的方法的诱惑非常大。此外,这似乎违反了单一责任原则,但这可能是一个品味问题
我会将生成的方法放在一个单独的文件(派生类或部分类声明)中。这样做的好处是您不需要解析器:如果未生成的类文件可能使用抽象或部分方法声明进行编译,那么您可以编译它,只需使用众所周知的反射机制即可获得所需的所有信息。您所需要的只是一个模板框架,如or,以生成代码。下面的代码进行替换,但在很大程度上取决于输入源文件的格式。 假设 Webmethod从前缀为“public void”的新行开始 参数在同一行上 开始和结束括号{和}在单独的行上。 代码可以优化,硬编码可以重新编码 感动的 用法
也可以对其进行修改以适应该方法。以下代码进行替换,但在很大程度上取决于输入源文件的格式。 假设 Webmethod从前缀为“public void”的新行开始 参数在同一行上 开始和结束括号{和}在单独的行上。 代码可以优化,硬编码可以删除。 用法
也可以修改此方法。resharper如何帮助我完成此操作?创建一个模板,获取当前方法,更改其名称,并使用新名称进行复制。这确实可以用最少的工作量使事情变得更简单。我只需要为每个函数填写webmethod名称,就是这样做的。15分钟创建模板,2小时转换所有Web服务。resharper如何帮助我完成此任务?创建一个获取当前方法的模板,更改其名称并使用新名称复制它。这确实可以通过最少的工作使事情变得更简单。我只需要为每个函数填写webmethod名称,就是这样做的。创建模板需要15分钟,转换所有Web服务需要2小时。如果问题变得更严重,请确保不要坚持使用正则表达式。它们可能可以做到这一点,但在一般情况下,它们做得不太好。我不会这么做:函数声明语法相当复杂。如果您忘记了一些边缘情况,例如参数之间的注释、参数上的属性、嵌套泛型类型,您的正则表达式将简单地忽略一个方法,而没有警告或错误-C不是常规语言,甚至不是此子集,如果您想解析它,请使用解析。有问题吗?使用正则表达式。现在你有两个问题:如果问题变得更大,一定不要坚持使用正则表达式。它们可能可以做到这一点,但在一般情况下,它们做得不太好。我不会这么做:函数声明语法相当复杂。如果您忘记了一些边缘情况,例如参数之间的注释、参数上的属性、嵌套泛型类型,您的正则表达式将简单地忽略一个方法,而没有警告或错误-C不是常规语言,甚至不是此子集,如果您想解析它,请使用解析。有问题吗?使用正则表达式。现在您有两个问题:+1建议使用CSharpCodeProvider.Parse,但使用CodeDOM生成代码是一个巨大的难题。我不觉得有那么难,而且这是一个相当小的任务,所以应该可以管理。我没有说这很难,我说这是一个麻烦;-生成一行C代码通常需要3-10行CodeDom代码。如果你使用模板引擎,你必须写一行:你想要生成的那行。很高兴知道。但是,对于我必须更改的100个Web服务来说,这有点过分了。这是行不通的,因为CSharpCodeProvider.Parse会引发一个问题。此CodeDomainProvider不支持此方法-请参阅+1以建议CSharpCodeProvider.Parse,但是使用CodeDOM生成代码是一个巨大的难题。我不觉得有那么难,而且这是一个相当小的任务,所以它应该是可管理的。我没有说这很难,我说这是一个麻烦;-生成一行C代码通常需要3-10行CodeDom代码。如果你使用模板引擎,你必须写一行:你想要生成的那行。很高兴知道。但是,对于我必须更改的100个Web服务来说,这有点过分了。这是行不通的,因为CSharpCodeProvider。Parse会引发一个问题,因为此CodeDomainProvider不支持此方法-请注意,这种解析器非常脆弱:如果属性是[Webmethod]编写的呢?或者[SomeAttribute,WebMethod]?如果属性和函数之间有xml注释呢?如果返回类型包含空格(例如Dictionary),该怎么办?如果函数中的注释包含字符“{”或“}”,该怎么办?如果同一行中不止一个括号,例如var data=new[]{1,2,3},该怎么办?你不能这样解析C。编写一个干净的解析器或使用解析器生成器为您完成它。@nikie,您是对的。只要与假设稍有偏差,代码就会中断。我不知道CodeGeneratorSystem.CodeDom类,它提供了一种更好的生成类的方法。这段代码可以作为一个起点。非常感谢你的代码。但我将使用一个标准解析器。注意,这种解析器非常脆弱:如果属性是[Webmethod]编写的,该怎么办?或者[SomeAttribute,WebMethod]?如果属性和函数之间有xml注释呢?如果返回类型包含空格(例如Dictionary),该怎么办?如果函数中的注释包含字符“{”或“}”,该怎么办?如果同一行中不止一个括号,例如var data=new[]{1,2,3},该怎么办?你不能这样解析C。编写一个干净的解析器或使用解析器生成器为您完成它。@nikie,您是对的。只要稍微偏离假设值,代码就会中断
是的。我不知道CodeGeneratorSystem.CodeDom类,它提供了一种更好的生成类的方法。这段代码可以作为一个起点。非常感谢你的代码。但我将使用一个标准解析器。应该更安全。
class CodeChanger
{
private Dictionary webMethodDictionary;
public CodeChanger()
{
webMethodDictionary = new Dictionary();
}
public void ChangeCode(string oldFilePath, string newFilePath)
{
StringBuilder newFileContents = new StringBuilder();
StringBuilder webserviceMethodContents = new StringBuilder();
Encoding iso88591Encoding = Encoding.GetEncoding("ISO-8859-1");
string readLine;
using (StreamReader streamReader = new StreamReader(oldFilePath, iso88591Encoding))
{
while ((readLine = streamReader.ReadLine()) != null)
{
if (!string.IsNullOrEmpty(readLine.Trim()))
{
if (string.Equals(readLine, "[Webmethod]"))
{
// Read the next line - method signature
if ((readLine = streamReader.ReadLine()) != null)
{
readLine = readLine.Trim();
if (readLine.StartsWith("public void"))
{
string methodName = readLine.Split(new char[] { ' ' })[2];
Webmethod webMethod = new Webmethod(methodName);
webMethodDictionary.Add(methodName, webMethod);
// Process parameters
ProcessParameters(readLine, methodName, webMethod);
// Process Body
if ((readLine = streamReader.ReadLine()) != null)
{
StringBuilder methodBody = new StringBuilder();
readLine = readLine.Trim();
if (string.Equals(readLine, "{"))
{
int bracketCounter = 1;
while ((readLine = streamReader.ReadLine()) != null)
{
if (string.Equals(readLine.Trim(), "}"))
{
bracketCounter--;
}
else if (string.Equals(readLine.Trim(), "{"))
{
bracketCounter++;
}
if (bracketCounter != 0)
{
methodBody.AppendLine(readLine);
}
else
{
break;
}
}
webMethod.AddBody(methodBody.ToString());
}
}
newFileContents.AppendLine(GenerateNewWebmethods(webMethod));
}
}
}
else
{
newFileContents.AppendLine(readLine);
}
}
else
{
newFileContents.AppendLine();
}
}
}
using (StreamWriter writer = new StreamWriter(newFilePath, false, iso88591Encoding))
{
writer.Write(newFileContents.ToString());
}
}
private static void ProcessParameters(string readLine, string methodName, Webmethod webMethod)
{
int positionOpenBrackets = string.Concat("public void ", methodName, " ").Length;
string parametersString = readLine.Substring(positionOpenBrackets).Trim();
parametersString = parametersString.TrimStart(new char[] { '(' });
parametersString = parametersString.TrimEnd(new char[] { ')' });
string[] parameters = parametersString.Split(new char[] { ',' });
foreach (string parameter in parameters)
{
string[] splitParameters = parameter.Trim().Split(new char[] { ' ' });
webMethod.AddParameter(splitParameters[0].Trim(), splitParameters[1].Trim());
}
}
private string GenerateNewWebmethods(Webmethod webmethod)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine(GenerateInternal(webmethod));
stringBuilder.AppendLine(GenerateBegin(webmethod));
stringBuilder.Append(GenerateEnd(webmethod));
return stringBuilder.ToString();
}
private string GenerateInternal(Webmethod webmethod)
{
StringBuilder stringBuilder = new StringBuilder();
string parametersString = GenerateParameterString(webmethod);
stringBuilder.AppendLine(string.Format("public void Internal{0} ({1}, AsyncCallback callback)",
webmethod.Name, parametersString.Trim().TrimEnd(',')));
stringBuilder.AppendLine("{");
stringBuilder.Append(webmethod.Body);
stringBuilder.AppendLine("}");
return stringBuilder.ToString();
}
private string GenerateEnd(Webmethod webmethod)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine(string.Format("public void End{0} (IAsyncResult asyncResult)", webmethod.Name));
stringBuilder.AppendLine("{");
stringBuilder.AppendLine("//Set return values");
stringBuilder.Append("}");
return stringBuilder.ToString();
}
private string GenerateBegin(Webmethod webmethod)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("[Webmethod]");
string parametersString = GenerateParameterString(webmethod);
stringBuilder.AppendLine(string.Format("public void Begin{0} ({1}, AsyncCallback callback, object asyncState)",
webmethod.Name, parametersString.Trim().TrimEnd(',')));
stringBuilder.AppendLine("{");
stringBuilder.AppendLine("//Queue InternalMyWebservice in a threadpool");
stringBuilder.AppendLine("}");
return stringBuilder.ToString();
}
private static string GenerateParameterString(Webmethod webmethod)
{
StringBuilder parametersStringBuilder = new StringBuilder();
foreach (MethodParameter parameter in webmethod.Parameters)
{
string parameterString = string.Concat(parameter.Type, " ", parameter.Name, ", ");
parametersStringBuilder.Append(parameterString);
}
return parametersStringBuilder.ToString();
}
}
class Webmethod
{
public IList Parameters { get; private set; }
public string Name { get; private set; }
public string Body { get; private set; }
public Webmethod(string name)
{
Parameters = new List();
Name = name;
}
public void AddParameter(string paramType, string paramName)
{
MethodParameter methodParameter = new MethodParameter
{
Type = paramType,
Name = paramName
};
Parameters.Add(methodParameter);
}
public void AddBody(string body)
{
Body = body;
}
}
class MethodParameter
{
public string Type { get; set; }
public string Name { get; set; }
}
CodeChanger cc = new CodeChanger();
cc.ChangeCode(@"D:\1.cs", @"D:\3.cs");