C#Reflection:用文本中的值替换所有出现的属性

时间:2015-11-12 14:51:04

标签: c# .net c#-4.0 reflection

我有一个像

这样的课程
public class MyClass {

  public string FirstName {get; set;}
  public string LastName {get; set;}

}

案例是,我有一个字符串文本,如

string str = "My Name is @MyClass.FirstName @MyClass.LastName";

我想要的是替换 @ MyClass.FirstName & @ MyClass.LastName ,其值使用反射分配给类中的对象FirstName和LastName。

请帮忙吗?

5 个答案:

答案 0 :(得分:5)

如果您想生成字符串,可以使用Linq枚举属性:

  MyClass test = new MyClass {
    FirstName = "John",
    LastName = "Smith",
  };

  String result = "My Name is " + String.Join(" ", test
    .GetType()
    .GetProperties(BindingFlags.Public | BindingFlags.Instance)
    .Where(property => property.CanRead)  // Not necessary
    .Select(property => property.GetValue(test)));

  // My Name is John Smith
  Console.Write(result);

如果您想在字符串中替换格式的种类),正则表达式很可能是您的选择以便解析字符串:

  String original = "My Name is @MyClass.FirstName @MyClass.LastName";
  String pattern = "@[A-Za-z0-9\\.]+";

  String result = Regex.Replace(original, pattern, (MatchEvaluator) ((match) => 
    test
      .GetType()
      .GetProperty(match.Value.Substring(match.Value.LastIndexOf('.') + 1))
      .GetValue(test) 
      .ToString() // providing that null can't be returned
  ));

  // My Name is John Smith
  Console.Write(result);

注意,为了获得实例(即不是static)属性值,您必须提供实例test上面的代码):

   .GetValue(test) 

所以 @MyClass 字符串中的部分是无用的,因为我们可以直接从实例获取类型:

   test.GetType()

修改:如果某些属性可以返回null作为值

 String result = Regex.Replace(original, pattern, (MatchEvaluator) ((match) => {
   Object v = test
     .GetType()
     .GetProperty(match.Value.Substring(match.Value.LastIndexOf('.') + 1))
     .GetValue(test);

   return v == null ? "NULL" : v.ToString(); 
 }));

答案 1 :(得分:3)

首先,我建议不要在string.Format等其他选项可用时使用反射。反射可以使您的代码更不易读,更难维护。无论哪种方式,你都可以这样做:

public void Main()
{
    string str = "My Name is @MyClass.FirstName @MyClass.LastName";
    var me = new MyClass { FirstName = "foo", LastName = "bar" };
    ReflectionReplace(str, me);
}

public string ReflectionReplace<T>(string template, T obj)
{    
    foreach (var property in typeof(T).GetProperties())
    {
        var stringToReplace = "@" + typeof(T).Name + "." + property.Name;
        var value = property.GetValue(obj);
        if (value == null) value = "";
        template = template.Replace(stringToReplace, value.ToString());
    }
    return template;
}

如果要向类中添加新属性并更新模板字符串以包含新值,则不需要进行其他更改。它还应该处理任何类的任何属性。

答案 2 :(得分:2)

使用Reflection您可以实现它,如下所示

MyClass obj = new MyClass() { FirstName = "Praveen", LaseName = "Paulose" };

        string str = "My Name is @MyClass.FirstName @MyClass.LastName";

        string firstName = (string)obj.GetType().GetProperty("FirstName").GetValue(obj, null);
        string lastName = (string)obj.GetType().GetProperty("LaseName").GetValue(obj, null);

        str = str.Replace("@MyClass.FirstName", firstName);
        str = str.Replace("@MyClass.LastName", lastName);

        Console.WriteLine(str);

您首先使用GetProperty找到相关的属性,然后使用GetValue找到其值

<强>更新

根据评论中要求的进一步澄清

您可以使用正则表达式来标识字符串中的所有占位符。即@ MyClass.Property。找到它们后,可以使用Type.GetType获取Type信息,然后使用上面显示的代码获取属性。但是,您需要命名空间来实例化类型。

答案 3 :(得分:0)

虽然已经五岁了,但我发现它很有用。

这是我对德米特里·拜琴科(Dmitry Bychenko)的改编,它也深入到了所有JSON字段中。

仅在一个级别上可用,但在某些情况下将使其递归。

Regex _replacementVarsRegex = new Regex(@"\{\{([\w\.]+)\}\}", RegexOptions.Compiled);
var result = "string with {{ObjectTypeName.PropertyName}} and json {{ObjectTypeName.JsonAsStringProperty.JsonProperty}}";
string ReplaceFor(object o) => _replacementVarsRegex.Replace(result, match =>
{
    if (o == null) return match.Value;
    var typeName = match.Value.Substring(0, match.Value.IndexOf('.')).TrimStart('{');
    var type = o.GetType();
    if (typeName != type.Name) return match.Value;
    var name = match.Value.Substring(match.Value.LastIndexOf('.') + 1).TrimEnd('}');
    var propertyInfo = type.GetProperty(name);
    var value = propertyInfo?.GetValue(o);
    var s = value?.ToString();
    if (match.Value.Contains(".Metadata."))
    {
        var jsonProperty = type.GetProperty("Metadata");
        var json = jsonProperty?.GetValue(o)?.ToString() ?? string.Empty;
        if (!string.IsNullOrWhiteSpace(json))
        {
            // var dObj = JsonConvert.DeserializeObject(json);
            var jObj = JObject.Parse(json);
            var val = jObj[name].Value<string>();
            s = val;
        }
    }

    return s ?? match.Value;
});

result = ReplaceFor(object1);
result = ReplaceFor(object2);
//...
result = ReplaceFor(objectn);

//remove any not answered, if desired
result = _replacementVarsRegex.Replace(result, string.Empty);

欢迎提出改进建议!

答案 4 :(得分:0)

最近在做一个项目,我最终需要类似的东西。要求是使用不会自然出现在我们的文本 @obj.property 中的占位符格式,因此使用了 @obj.property@。此外,处理级联令牌(令牌取决于令牌)和来自 IEnumerable 的数据的处理,例如:["Cat", "Dog", "Chicken"] 需要在文本中显示为 "Cat, Dog, Chicken" .

我已经创建了一个 library 并有一个 NuGet 包,以便更快地将此功能融入您的代码中。