'{' <> [ ':' < > ] [ '|' < > ] '}'
, {User.GetFIO()|}! , : function PrintMyName() {{ Console.WriteLine("My name is {{0}}. I'm {{1}}.", "{UserName|}", {User.Age:0}); }} {Now:dd MMMM yyyy} {Now:HH:mm:ss}
: {User.Account[0].GetSomeArrayMethod("a", true, 8.5, null)[5,8].Length:0000|NULL}
/// <summary> /// /// </summary> public abstract class PatternElement { /// <summary> /// /// </summary> public virtual int EstimatedLength { get { return 0; } } /// <summary> /// /// </summary> public abstract string GetNullValue(); }
public class StringConstantElement : PatternElement { public string Value { get; set; } public override int EstimatedLength { get { return Value == null ? 0 : Value.Length; } } public override string GetNullValue() { return Value; } } public class ExpressionElement : PatternElement { public string Path { get; set; } public string FormatString { get; set; } public string DefaultValue { get; set; } public override int EstimatedLength { get { return Math.Max(20, DefaultValue == null ? 0 : DefaultValue.Length); } } public override string GetNullValue() { return DefaultValue; } }
public interface IPatternParser { IEnumerable<PatternElement> Parse(string pattern); }
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Genesis.Patternizer { /// <summary> /// /// </summary> public class BracePatternParser : IPatternParser { private object _lock = new object(); private HashSet<char> PATH_TERMINATOR_CHARS; private HashSet<char> FORMAT_TERMINATOR_CHARS; private HashSet<char> PATTERN_TERMINATOR_CHARS; private string pattern; // private int length; // private int length_1; // private int index; // private StringBuilder constantBuilder; private StringBuilder expressionBuilder; /// <summary> /// /// </summary> public BracePatternParser() { PATH_TERMINATOR_CHARS = new HashSet<char>(":|}".ToCharArray()); FORMAT_TERMINATOR_CHARS = new HashSet<char>("|}".ToCharArray()); PATTERN_TERMINATOR_CHARS = new HashSet<char>("}".ToCharArray()); } /// <summary> /// /// </summary> /// <param name="chars"> - </param> /// <returns></returns> private string ParsePatternPath(HashSet<char> chars) { // expressionBuilder.Clear(); Stack<char> brackets = new Stack<char>(); bool ignoreBrackets = false; for (index++; index < length; index++) { char c = pattern[index]; if (c == '(') { brackets.Push(c); expressionBuilder.Append(c); } else if (c == ')') { if (brackets.Peek() == '(') { brackets.Pop(); } else { // ignoreBrackets = true; } expressionBuilder.Append(c); } else if (c == '[') { brackets.Push(c); expressionBuilder.Append(c); } else if (c == ']') { if (brackets.Peek() == '[') { brackets.Pop(); } else { // ignoreBrackets = true; } expressionBuilder.Append(c); } else if (chars.Contains(c) && (ignoreBrackets || brackets.Count == 0)) { // break; } else { expressionBuilder.Append(c); } } return expressionBuilder.Length == 0 ? null : expressionBuilder.ToString(); } /// <summary> /// /// </summary> /// <param name="chars"> - </param> /// <returns></returns> private string ParsePatternPart(HashSet<char> chars) { // expressionBuilder.Clear(); for (index++; index < length; index++) { char c = pattern[index]; if (c == '\\') { // if (index < length_1) { expressionBuilder.Append(pattern[++index]); } } else if (chars.Contains(c)) { // break; } else { expressionBuilder.Append(c); } } return expressionBuilder.Length == 0 ? null : expressionBuilder.ToString(); } /// <summary> /// /// </summary> /// <returns></returns> private ExpressionElement ParsePattern() { string path = ParsePatternPath(PATH_TERMINATOR_CHARS); if (path == null) { // // (}) for (; index < length; index++) { char c = pattern[index]; if (c == '\\') { index++; } else if (c == '}') { break; } } return null; } else { ExpressionElement element = new ExpressionElement(path); // if (index < length && pattern[index] == ':') { // element.FormatString = ParsePatternPart(FORMAT_TERMINATOR_CHARS); } if (index < length && pattern[index] == '|') { // element.DefaultValue = ParsePatternPart(PATTERN_TERMINATOR_CHARS); } return element; } } /// <summary> /// /// </summary> /// <param name="pattern"> </param> /// <returns></returns> public IEnumerable<PatternElement> Parse(string pattern) { lock (_lock) { if (pattern == null) { // yield break; } else if (string.IsNullOrWhiteSpace(pattern)) { yield return new StringConstantElement(pattern); yield break; } // this.pattern = pattern; // length = pattern.Length; length_1 = length - 1; index = 0; // constantBuilder = new StringBuilder(); expressionBuilder = new StringBuilder(); // for (; index < length; index++) { char c = pattern[index]; if (c == '{') { if (index < length_1 && pattern[index + 1] == c) { // '{' constantBuilder.Append(c); index++; } else { // if (constantBuilder.Length != 0) { yield return new StringConstantElement(constantBuilder.ToString()); // constantBuilder.Clear(); } var patternElement = ParsePattern(); if (patternElement != null) { yield return patternElement; } } } else if (c == '}') { if (index < length_1 && pattern[index + 1] == c) { // '}' constantBuilder.Append(c); index++; } else { // , constantBuilder.Append(c); } } else { constantBuilder.Append(c); } } // if (constantBuilder.Length != 0) { yield return new StringConstantElement(constantBuilder.ToString()); } // this.pattern = null; constantBuilder = null; expressionBuilder = null; index = length = length_1 = 0; } } } }
public interface IBuilderGenerator { Func<object, string> GenerateBuilder(List<PatternElement> pattern, Type modelType); }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using BUILDER = System.Func<object, string>; namespace Genesis.Patternizer { /// <summary> /// - /// </summary> public class Patternizator { #region Declarations private PatternizatorOptions _options; // private string _pattern; // private List<PatternElement> _elements; // private Dictionary<Type, BUILDER> _builders; // #endregion #region Properties /// <summary> /// /// </summary> public string Pattern { get { return _pattern; } set { _pattern = value; PreparePattern(); } } #endregion #region Constructors /// <summary> /// /// </summary> public Patternizator() { _options = PatternizatorOptions.Default; _builders = new Dictionary<Type, BUILDER>(); } /// <summary> /// /// </summary> /// <param name="pattern"> </param> public Patternizator(string pattern) { _options = PatternizatorOptions.Default; Pattern = pattern; } /// <summary> /// /// </summary> /// <param name="options"> </param> public Patternizator(PatternizatorOptions options) { _options = options; _builders = new Dictionary<Type, BUILDER>(); } /// <summary> /// /// </summary> /// <param name="pattern"> </param> /// <param name="options"> </param> public Patternizator(string pattern, PatternizatorOptions options) { _options = options; Pattern = pattern; } #endregion #region Private methods /// <summary> /// /// </summary> private void PreparePattern() { // _elements = _options.Parser.Parse(_pattern).ToList(); // _builders = new Dictionary<Type, BUILDER>(); // //string template = string.Join(Environment.NewLine, _elements.Select(e => System.Text.RegularExpressions.Regex.Replace(e.ToString(), @"\s+", " ").Trim()).ToArray()); } #endregion #region Public methods /// <summary> /// /// </summary> /// <param name="model"> </param> /// <returns></returns> public string Generate(object model) { // Type modelType = model == null ? null : model.GetType(); Type modelTypeKey = modelType ?? typeof(DBNull); // BUILDER builder; if (!_builders.TryGetValue(modelTypeKey, out builder)) { // builder = _options.BuilderGenerator.GenerateBuilder(_elements, modelType); _builders.Add(modelTypeKey, builder); } // return builder(model); } #endregion } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Genesis.Patternizer { /// <summary> /// /// </summary> public class PatternizatorOptions { /// <summary> /// /// </summary> public IPatternParser Parser { get; set; } /// <summary> /// /// </summary> public IBuilderGenerator BuilderGenerator { get; set; } #region Default private static PatternizatorOptions _default; /// <summary> /// /// </summary> public static PatternizatorOptions Default { get { if (_default == null) { _default = new PatternizatorOptions { Parser = new BracePatternParser(), BuilderGenerator = new ReflectionBuilderGenerator(), }; } return _default; } } #endregion } }
// string pattern = GetPattern(); // Patternizator patternizator = new Patternizator(pattern); // User user = new User { Surname = RandomElement(rnd, SURNAMES), Name = RandomElement(rnd, NAMES), Patronymic = RandomElement(rnd, PATRONYMICS), // 1950 - 1990 Birthdate = new DateTime(1950, 1, 1).AddDays(rnd.NextDouble() * 40.0 * 365.25) }; var model = new { User = user, UserName = user.Name, Now = DateTime.Now, }; // string text = patternizator.Generate(model);
public string Generate(object input) { if (input == null) { // return @", ! , : function PrintMyName() { Console.WriteLine("My name is {0}. I'm {1}.", "", 0); } "; } else { Model model = input as Model; StringBuilder sb = new StringBuilder(); sb.Append(", "); // if (model.User != null) { var m_GetFIO = model.User.GetFIO(); if (m_GetFIO != null) { sb.Append(m_GetFIO); } else { sb.Append(""); // } } else { sb.Append(""); // } sb.Append("!\r\n , :\r\n\r\n ..."); // \\ .. return sb.ToString(); } }
// var genMethod = new DynamicMethod("< >", typeof(< >), new Type[] { typeof(< 1>), typeof(< 2>), ..., typeof(< N>) }, true); // - ( IL- CIL-) var cs = genMethod.GetILGenerator(); // // ... // cs.Emit(OpCodes.Ret); // return genMethod.CreateDelegate(typeof(< >)) as < >;
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; namespace ILDasm { class Program { #region Static static void Main(string[] args) { new Program().Run(); } #endregion public void Run() { string basePath = AppDomain.CurrentDomain.BaseDirectory; string exeName = Path.Combine(basePath, AppDomain.CurrentDomain.FriendlyName.Replace(".vshost", "")); Process.Start(@"C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\x64\ildasm.exe", string.Format(@"/item:ILDasm.TestClass::DoIt ""{0}"" /text /output:code.il", exeName)); } } public class TestClass { public string DoIt(object value) { StringBuilder sb = new StringBuilder(); return sb.ToString(); } } }
IL_0000: newobj instance void [mscorlib]System.Text.StringBuilder::.ctor() IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: callvirt instance string [mscorlib]System.Object::ToString() IL_000c: ret
IL_0000: ldarg.1 IL_0001: ldarg.2 IL_0002: add IL_0003: ldarg.3 IL_0004: mul
cs.Emit(OpCodes.Ldarg_1); cs.Emit(OpCodes.Ldarg_2); cs.Emit(OpCodes.Add); cs.Emit(OpCodes.Ldarg_3); cs.Emit(OpCodes.Mul);
/// <summary> /// /// </summary> /// <param name="pattern"> </param> /// <param name="modelType"> </param> /// <returns></returns> public virtual BUILDER GenerateBuilder(List<PatternElement> pattern, Type modelType) { if (modelType == null) { // , StringBuilder sb = new StringBuilder(); foreach (PatternElement item in pattern) { string nullValue = item.GetNullValue(); if (nullValue != null) { sb.Append(nullValue); } } string value = sb.ToString(); return (m) => value; } else { // string methodName = "Generate_" + Guid.NewGuid().ToString().Replace("-", ""); // var genMethod = new DynamicMethod(methodName, typeof(string), new Type[] { typeof(object) }, true); // var cs = genMethod.GetILGenerator(); var sb = cs.DeclareLocal(typeof(StringBuilder)); var m = cs.DeclareLocal(modelType); ReflectionBuilderGeneratorContext context = new ReflectionBuilderGeneratorContext { Generator = cs, ModelType = modelType, VarSB = sb, VarModel = m, }; // cs.Emit(OpCodes.Ldarg_0); cs.Emit(OpCodes.Isinst, modelType); cs.Emit(OpCodes.Stloc, m); // StringBuilder cs.Emit(OpCodes.Ldc_I4, pattern.Sum(e => e.EstimatedLength)); cs.Emit(OpCodes.Newobj, typeof(StringBuilder).GetConstructor(new Type[] { typeof(int) })); cs.Emit(OpCodes.Stloc, sb); foreach (PatternElement item in pattern) { MethodInfo processor; if (_dicProcessors.TryGetValue(item.GetType(), out processor)) { // processor.Invoke(processor.IsStatic ? null : this, new object[] { context, item }); } } cs.Emit(OpCodes.Ldloc, sb); cs.Emit(OpCodes.Callvirt, typeof(object).GetMethod("ToString", Type.EmptyTypes)); cs.Emit(OpCodes.Ret); return genMethod.CreateDelegate(typeof(BUILDER)) as BUILDER; } }
[PatternElement(typeof(StringConstantElement))] protected virtual void GenerateStringConstantIL(ReflectionBuilderGeneratorContext context, StringConstantElement element) { if (element.Value != null) { WriteSB_Constant(context, element.Value); } } /// <summary> /// StringBuilder /// </summary> /// <param name="context"> </param> /// <param name="value"> </param> protected virtual void WriteSB_Constant(ReflectionBuilderGeneratorContext context, string value) { if (value != null) { var cs = context.Generator; cs.Emit(OpCodes.Ldloc, context.VarSB); cs.Emit(OpCodes.Ldstr, value); cs.Emit(OpCodes.Callvirt, _dicStringBuilderAppend[typeof(string)]); cs.Emit(OpCodes.Pop); } }
/// <summary> /// /// </summary> private void Run() { // string outputPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Result"); if (!Directory.Exists(outputPath)) Directory.CreateDirectory(outputPath); Random rnd = new Random(0); Stopwatch sw = new Stopwatch(); // string pattern = GetPattern(); // string text; double patternTotal = 0; // () double patternInitialization; // () double patternFirst = 0; // () double manualTotal = 0; // () // sw.Restart(); Patternizator patternizator = new Patternizator(pattern); sw.Stop(); patternInitialization = sw.Elapsed.TotalMilliseconds; Console.WriteLine(" {0} (v. {1})", patternizator.GetType().Assembly.GetName().Name, patternizator.GetType().Assembly.GetName().Version); // for (int i = 0; i < COUNT_PATTERNIZATOR; i++) { // User user = new User { Surname = RandomElement(rnd, SURNAMES), Name = RandomElement(rnd, NAMES), Patronymic = RandomElement(rnd, PATRONYMICS), // 1950 - 1990 Birthdate = new DateTime(1950, 1, 1).AddDays(rnd.NextDouble() * 40.0 * 365.25) }; var model = new { User = user, UserName = user.Name, Now = DateTime.Now, }; // sw.Restart(); text = patternizator.Generate(model); sw.Stop(); patternTotal += sw.Elapsed.TotalMilliseconds; if (i == 0) { patternFirst = sw.Elapsed.TotalMilliseconds; } // if (i < COUNT_MANUAL) { // ! // - Replace sw.Restart(); { StringBuilder sb = new StringBuilder(pattern); DateTime now = DateTime.Now; sb.Replace("{User.GetFIO()|}", model.User.GetFIO() ?? ""); sb.Replace("{UserName|}", model.UserName ?? ""); sb.Replace("{User.Age:0}", model.User.Age.ToString("0")); sb.Replace("{Now:dd MMMM yyyy}", now.ToString("dd MMMM yyyy")); sb.Replace("{Now:HH:mm:ss}", now.ToString("HH:mm:ss")); text = sb.ToString(); } sw.Stop(); manualTotal += sw.Elapsed.TotalMilliseconds; } } WriteHeader(""); WriteElapsedTime(" ", patternInitialization); WriteElapsedTime(" ", patternFirst); Console.WriteLine(); WriteElapsedTime(string.Format(" {0} ", COUNT_PATTERNIZATOR), patternTotal); WriteElapsedTime(" ", patternTotal / COUNT_PATTERNIZATOR); WriteHeader(" ()"); WriteElapsedTime(string.Format(" {0} ", COUNT_MANUAL), manualTotal); WriteElapsedTime(" ", manualTotal / COUNT_MANUAL); Console.WriteLine(); Console.WriteLine(" ..."); Console.ReadKey(); }
Source: https://habr.com/ru/post/251765/
All Articles