C# 反射:用文本中的值替换所有出现的 属性
C# Reflection: replace all occurrence of property with value in text
我有一个class喜欢
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分配给 class.
中的对象 FirstName 和 LastName
有什么帮助吗?
使用反射你可以实现如下所示
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 获取类型信息,然后使用上面显示的代码获取属性。但是,您将需要命名空间来实例化类型。
首先,当 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;
}
如果您想向 class 添加新的 属性 并更新您的模板字符串以包含新值,则无需进行其他更改。它还应该处理任何 class.
上的任何属性
如果你想生成字符串你可以使用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);
请注意,为了获得 instance(即不是 static
)属性 值,您必须提供 instance(上面代码中的test
):
.GetValue(test)
所以字符串中的@MyClass部分没用,因为我们可以直接从实例中获取类型:
test.GetType()
编辑:如果某些属性可以returnnull
作为值
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();
}));
虽然已经五年了,但我发现它很有用。
这是我对 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);
欢迎提出改进建议!
最近在做一个项目时,我最终需要类似的东西。要求是使用占位符格式,这种格式不会自然出现在我们的文本中 @obj.property 可能有,所以使用了 @obj.property@。另外,处理级联令牌(令牌依赖于令牌)和处理来自 IEnumerable 的数据,例如:["Cat", "Dog", "Chicken"] 需要在文本中显示为“Cat, Dog, Chicken” .
我有一个class喜欢
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分配给 class.
中的对象 FirstName 和 LastName有什么帮助吗?
使用反射你可以实现如下所示
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 获取类型信息,然后使用上面显示的代码获取属性。但是,您将需要命名空间来实例化类型。
首先,当 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;
}
如果您想向 class 添加新的 属性 并更新您的模板字符串以包含新值,则无需进行其他更改。它还应该处理任何 class.
上的任何属性如果你想生成字符串你可以使用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);
请注意,为了获得 instance(即不是 static
)属性 值,您必须提供 instance(上面代码中的test
):
.GetValue(test)
所以字符串中的@MyClass部分没用,因为我们可以直接从实例中获取类型:
test.GetType()
编辑:如果某些属性可以returnnull
作为值
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();
}));
虽然已经五年了,但我发现它很有用。
这是我对 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);
欢迎提出改进建议!
最近在做一个项目时,我最终需要类似的东西。要求是使用占位符格式,这种格式不会自然出现在我们的文本中 @obj.property 可能有,所以使用了 @obj.property@。另外,处理级联令牌(令牌依赖于令牌)和处理来自 IEnumerable 的数据,例如:["Cat", "Dog", "Chicken"] 需要在文本中显示为“Cat, Dog, Chicken” .