从输入字符串中获取字符串形式的属性名

本文关键字:字符串 属性 获取 输入 | 更新日期: 2023-09-27 18:16:54

我目前正在创建一个模块,将使用Gembox在word中创建合并字段。c#文档。首先,我只想说这是我的任务,所以不管这样做是不是不好,这是他们想要的。

我有一个Windows窗体应用程序,其中有一个文本框和一个按钮。在文本框中,他们希望能够粘贴dto/model,例如:

"public class Example 
{
    public string Name { get; set; }
    public string Surname { get; set; }
    public string Cellphone { get; set; }
    public string Address { get; set; }
    public string CompanyName { get; set; }
    public DateTime CurrentDate { get; set; }  
}"

我已经有逻辑添加合并字段word与一个方法,我在一个字符串[],其中包含所有合并字段的名称。

问题是:我需要能够以某种方式子字符串这个大字符串上面包含一个dto/模型写在文本框中的字符串,获得属性名称并将它们添加到string[],因为它们将是合并字段名称。

我希望我能解释清楚。这是我的第一个问题,我不习惯用英语解释我的问题。

编辑:要指定问题:我需要从这个字符串中获取属性名称,并将它们放入string[]:

string s = @"public string Name { get; set; }
  public string Surname { get; set; }
  public string Cellphone { get; set; }
  public string Address { get; set; }
  public string CompanyName { get; set; }
  public DateTime CurrentDate { get; set; }"

从输入字符串中获取字符串形式的属性名

我认为也许你应该解析这个文本(使用解析器而不是自己的解决方案),然后搜索语法树来查找属性名称。我想到了类似的东西:

使用NRefactory分析c#代码

这段代码返回完整的树或错误(我使用NRefactory,但你可以使用Roslyn):

var parser = new CSharpParser();
var syntaxTree = parser.Parse(programCode);

syntaxTree字段查找属性。

示例代码:

const string code = @"public class Example {
    public string Name { get; set; }
    public string Surname { get; set; }
    public string Cellphone { get; set; }
    public string Address { get; set; }
    public string CompanyName { get; set; }
    public DateTime CurrentDate { get; set; }
}";
var syntaxTree = new CSharpParser().Parse(code, "program.cs");
var listOfPropertiesNames = syntaxTree.Children
    .SelectMany(astParentNode => astParentNode.Children)
    .OfType<PropertyDeclaration>()
    .Select(astPropertyNode => astPropertyNode.Name)
    .ToList();

您可以使用CSharpCodeProvider类将您的代码编译为程序集,然后使用反射在编译后的程序集中查找类型。

var sourcePart = @"public class Example 
{
    public string Name { get; set; }
    public string Surname { get; set; }
    public string Cellphone { get; set; }
    public string Address { get; set; }
    public string CompanyName { get; set; }
    public DateTime CurrentDate { get; set; }
}";
    var sourceTemplate = @"using System;
    @code
";
var code = sourceTemplate.Replace("@code", sourcePart);
CSharpCodeProvider c = new CSharpCodeProvider();
CompilerParameters cp = new CompilerParameters();
CompilerResults cr = c.CompileAssemblyFromSource(cp, code);
if (cr.Errors.Count > 0)
{
    MessageBox.Show("ERROR: " + cr.Errors[0].ErrorText,
        "Error evaluating cs code", MessageBoxButtons.OK,
           MessageBoxIcon.Error);
    return;
}
var a = cr.CompiledAssembly;
var type = a.GetTypes().Single();
string[] propertyNames = type.GetProperties().Select(p => p.Name).ToArray();

更新:但是请记住,在应用域中加载的类型不能被卸载,并且会一直消耗内存,直到应用程序退出。

因此,如果用户经常使用这个函数,内存将被增量地消耗。

如果这成为一个问题,你可以通过创建一个单独的应用域或生成另一个进程来解决这个问题,但这是另一个问题。

您可以创建自定义静态方法来解析文本。它所做的是从一个索引'{'跳到下一个索引的字符串向后并检查是否有'('或')'字符(这表明它是一个方法而不是一个属性,它应该跳过它)并向后查找属性的开始。之后,它提取值,然后跳转到'{' char的下一个索引,等等:

    static string[] GetProperties(string dirty)
    {
        List<string> properties = new List<string>();
        int i = dirty.IndexOf("{ ");
        StringBuilder sb = new StringBuilder();
        int propEndIndex = -1; int i2 = -1;
        for (; i != -1; i = dirty.IndexOf("{ ", i + 1))
        {
            i2 = i - 1;
            for (; dirty[i2] == ' '; i2--) { }
            if (dirty[i2] == '(' || dirty[i2] == ')') continue;
            propEndIndex = i2 + 1;
            for (; dirty[i2] != ' '; i2--) { }                
            for (i2++; i2 < propEndIndex; i2++)
                sb.Append(dirty[i2]);                
            properties.Add(sb.ToString());
            sb.Clear();
        }
        return properties.ToArray();
    }

用法示例:

       Stopwatch sw = new Stopwatch();
        var s = @"public class Example 
                {
                   public string Name { get; set; }
                   public string Surname { get; set; }
                   public string Cellphone { get; set; }
                   public string Address { get; set; }
                   public string CompanyName { get; set; }
                   public DateTime CurrentDate { get; set; }  
                   public void MyMethod() { }
                }";
        sw.Start();
        string[] props =  GetProperties(s);
        sw.Stop();
        foreach (var item in props)
            Console.WriteLine(item);
        Console.WriteLine("'n'nMethod is executed in " + sw.ElapsedMilliseconds + " ms");
        Console.ReadKey();
输出:

Name
Surname 
CellPhone
Address
CompanyName 
CurrentDate
Method is executed in 1 ms