আমি বহুবার এই সমস্যার মুখোমুখি হয়েছি এবং আমি মনে করি যে আমি একটি সহজ সমাধান নিয়ে এসেছি।
প্রথমদিকে আমি ডেকরেটার প্যাটার্ন নিয়ে গিয়েছিলাম এবং ম্যানুয়ালি প্রতিটি পদ্ধতি প্রয়োগ করেছিলাম, যখন আপনার শত পদ্ধতি রয়েছে তখন এটি খুব ক্লান্তিকর হয়ে ওঠে।
তারপরে আমি পোস্টশার্প ব্যবহার করার সিদ্ধান্ত নিয়েছি তবে একটি সাধারণ লাইব্রেরি কেবলমাত্র এমন কিছু করতে যা আমি (প্রচুর) সহজ কোড দিয়ে অর্জন করতে পারি তার ধারণা পছন্দ করি না।
আমি তখন স্বচ্ছ প্রক্সি রুটে নেমে গেলাম যা মজাদার ছিল তবে চালকালে আইএল নির্গতভাবে জড়িত জড়িত ছিল এবং এমন কোনও কিছু হবে না যা আমি একটি উত্পাদন পরিবেশে করতে চাই।
আমি সম্প্রতি ডিজাইনের সময় ডেকোরেটর প্যাটার্নটি স্বয়ংক্রিয়ভাবে প্রয়োগ করতে টি 4 টেম্পলেটগুলি ব্যবহার করার সিদ্ধান্ত নিয়েছি, এটি দেখা যাচ্ছে যে টি 4 টেমপ্লেটগুলি আসলে কাজ করা বেশ কঠিন এবং আমি কোড বেলো তৈরি করার জন্য আমার এটি দ্রুত করা দরকার। এটি দ্রুত এবং নোংরা (এবং এটি বৈশিষ্ট্যগুলি সমর্থন করে না) তবে আশা করি যে কেউ এটির কাজে লাগবে।
কোডটি এখানে:
var linesToUse = code.Split(Environment.NewLine.ToCharArray()).Where(l => !string.IsNullOrWhiteSpace(l));
string classLine = linesToUse.First();
// Remove the first line this is just the class declaration, also remove its closing brace
linesToUse = linesToUse.Skip(1).Take(linesToUse.Count() - 2);
code = string.Join(Environment.NewLine, linesToUse).Trim()
.TrimStart("{".ToCharArray()); // Depending on the formatting this may be left over from removing the class
code = Regex.Replace(
code,
@"public\s+?(?'Type'[\w<>]+?)\s(?'Name'\w+?)\s*\((?'Args'[^\)]*?)\)\s*?\{\s*?(throw new NotImplementedException\(\);)",
new MatchEvaluator(
match =>
{
string start = string.Format(
"public {0} {1}({2})\r\n{{",
match.Groups["Type"].Value,
match.Groups["Name"].Value,
match.Groups["Args"].Value);
var args =
match.Groups["Args"].Value.Split(",".ToCharArray())
.Select(s => s.Trim().Split(" ".ToCharArray()))
.ToDictionary(s => s.Last(), s => s.First());
string call = "_decorated." + match.Groups["Name"].Value + "(" + string.Join(",", args.Keys) + ");";
if (match.Groups["Type"].Value != "void")
{
call = "return " + call;
}
string argsStr = args.Keys.Any(s => s.Length > 0) ? ("," + string.Join(",", args.Keys)) : string.Empty;
string loggedCall = string.Format(
"using (BuildLogger(\"{0}\"{1})){{\r\n{2}\r\n}}",
match.Groups["Name"].Value,
argsStr,
call);
return start + "\r\n" + loggedCall;
}));
code = classLine.Trim().TrimEnd("{".ToCharArray()) + "\n{\n" + code + "\n}\n";
এখানে একটি উদাহরণ:
public interface ITestAdapter : IDisposable
{
string TestMethod1();
IEnumerable<string> TestMethod2(int a);
void TestMethod3(List<string[]> a, Object b);
}
তারপরে লগিংস্টেস্টএডাপ্টার নামে একটি শ্রেণি তৈরি করুন যা ITestAdapter প্রয়োগ করে, সমস্ত পদ্ধতি অটো বাস্তবায়নের জন্য ভিজ্যুয়াল স্টুডিও পান এবং তারপরে উপরের কোডের মাধ্যমে চালনা করুন। আপনার তখন এরকম কিছু হওয়া উচিত:
public class LoggingTestAdapter : ITestAdapter
{
public void Dispose()
{
using (BuildLogger("Dispose"))
{
_decorated.Dispose();
}
}
public string TestMethod1()
{
using (BuildLogger("TestMethod1"))
{
return _decorated.TestMethod1();
}
}
public IEnumerable<string> TestMethod2(int a)
{
using (BuildLogger("TestMethod2", a))
{
return _decorated.TestMethod2(a);
}
}
public void TestMethod3(List<string[]> a, object b)
{
using (BuildLogger("TestMethod3", a, b))
{
_decorated.TestMethod3(a, b);
}
}
}
এটি সমর্থনকারী কোড সহ:
public class DebugLogger : ILogger
{
private Stopwatch _stopwatch;
public DebugLogger()
{
_stopwatch = new Stopwatch();
_stopwatch.Start();
}
public void Dispose()
{
_stopwatch.Stop();
string argsStr = string.Empty;
if (Args.FirstOrDefault() != null)
{
argsStr = string.Join(",",Args.Select(a => (a ?? (object)"null").ToString()));
}
System.Diagnostics.Debug.WriteLine(string.Format("{0}({1}) @ {2}ms", Name, argsStr, _stopwatch.ElapsedMilliseconds));
}
public string Name { get; set; }
public object[] Args { get; set; }
}
public interface ILogger : IDisposable
{
string Name { get; set; }
object[] Args { get; set; }
}
public class LoggingTestAdapter<TLogger> : ITestAdapter where TLogger : ILogger,new()
{
private readonly ITestAdapter _decorated;
public LoggingTestAdapter(ITestAdapter toDecorate)
{
_decorated = toDecorate;
}
private ILogger BuildLogger(string name, params object[] args)
{
return new TLogger { Name = name, Args = args };
}
public void Dispose()
{
_decorated.Dispose();
}
public string TestMethod1()
{
using (BuildLogger("TestMethod1"))
{
return _decorated.TestMethod1();
}
}
public IEnumerable<string> TestMethod2(int a)
{
using (BuildLogger("TestMethod2", a))
{
return _decorated.TestMethod2(a);
}
}
public void TestMethod3(List<string[]> a, object b)
{
using (BuildLogger("TestMethod3", a, b))
{
_decorated.TestMethod3(a, b);
}
}
}