StringTemplate
클래스는 사용자의 필요에 맞게 수정 될 수 있습니다. 이는 String.Format
처럼 동작합니다. 큰 차이가 있습니다. 인덱스가 아닌 자리 표시 자의 이름을 사용할 수 있습니다. 형식을 지정할 값은 IDictionary<string, object>
또는 임의의 개체로 지정할 수 있습니다.이 경우 각 개체 틀은 같은 이름의 속성 값으로 대체됩니다. 예를 들어
: 동일한 템플릿을 여러 번 사용해야하는 경우
// with a dictionary :
var values = new Dictionary<string, object>
{
{ "Title", "Mr." },
{ "LastName", "Smith" }
};
string a = StringTemplate.Format("Hello {Title} {LastName}", values);
// with an anonymous type :
string b = StringTemplate.Format(
"Hello {Title} {LastName}",
new { Title = "Mr.", LastName = "Smith" });
, 당신은 StringTemplate
의 인스턴스를 생성하고 성능 향상을 위해 재사용 할 수 있습니다 (템플릿 문자열은 한 번만 구문 분석 할 것입니다).
String.Format
과 같은 형식 수정자를 지정할 수도 있습니다.
public class StringTemplate
{
private string _template;
private static Regex _regex = new Regex(@"(?<open>{+)(?<key>\w+)(?<format>:[^}]+)?(?<close>}+)", RegexOptions.Compiled);
public StringTemplate(string template)
{
template.CheckArgumentNull("template");
this._template = template;
ParseTemplate();
}
private string _templateWithIndexes;
private List<string> _placeholders;
private void ParseTemplate()
{
_placeholders = new List<string>();
MatchEvaluator evaluator = (m) =>
{
if (m.Success)
{
string open = m.Groups["open"].Value;
string close = m.Groups["close"].Value;
string key = m.Groups["key"].Value;
string format = m.Groups["format"].Value;
if (open.Length % 2 == 0)
return m.Value;
open = RemoveLastChar(open);
close = RemoveLastChar(close);
if (!_placeholders.Contains(key))
{
_placeholders.Add(key);
}
int index = _placeholders.IndexOf(key);
return string.Format("{0}{{{1}{2}}}{3}", open, index, format, close);
}
return m.Value;
};
_templateWithIndexes = _regex.Replace(_template, evaluator);
}
private string RemoveLastChar(string str)
{
if (str.Length > 1)
return str.Substring(0, str.Length - 1);
else
return string.Empty;
}
public static implicit operator StringTemplate(string s)
{
return new StringTemplate(s);
}
public override string ToString()
{
return _template;
}
public string Format(IDictionary<string, object> values)
{
values.CheckArgumentNull("values");
object[] array = new object[_placeholders.Count];
for(int i = 0; i < _placeholders.Count; i++)
{
string key = _placeholders[i];
object value;
if (!values.TryGetValue(key, out value))
{
value = string.Format("{{{0}}}", key);
}
array[i] = value;
}
return string.Format(_templateWithIndexes, array);
}
private IDictionary<string, object> MakeDictionary(object obj)
{
Dictionary<string, object> dict = new Dictionary<string, object>();
Type type = obj.GetType();
foreach (string propName in _placeholders)
{
var prop = type.GetProperty(propName);
if (prop != null)
dict.Add(propName, prop.GetValue(obj, null));
}
return dict;
}
public string Format(object values)
{
return Format(MakeDictionary(values));
}
public static string Format(string template, IDictionary<string, object> values)
{
return new StringTemplate(template).Format(values);
}
public static string Format(string template, object values)
{
return new StringTemplate(template).Format(values);
}
}
또한 사용할 수 있습니다 여기에
코드의 ... ,이 클래스는, 약간의 조정이 필요합니다 당신의 정확한 요구에 맞게하지만 너무 열심히하지 않아야 prop.GetGetMethod() 대신 prop.GetValue (user, null) 호출 (...) –
어떤 객체를 사용하는 메소드로 이것을 래핑하는 것이 가능합니까? – Blankman
@Fadrian : 고마워, 그거 좋은 제안이야! @Blankman : 예, 모든 객체에서 작동 할 수 있습니다. 일반 메소드에 포장하고'typeof (T)'를 사용하거나 (객체 유형이 컴파일 타임에 알려짐)'user.GetType()'을 사용하여'object' 유형의 인자의 현재 유형을 실행 시간. –