public
Last active

Linqpad Extensions - `.Title()`, `.DumpFormat(tokens)`, `.Perf(task)`, `.Vs(tasks)`

  • Download Gist
LinqPad.MyExtensions.cs
C#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
/// <summary>Silly convenience initializer for creating Vs tasks with a dictionary;
/// can use <code>new Perf { { "task1", n => whatever }, {"task2", n => bar}...}</code>
/// <para>see http://stackoverflow.com/a/14000325/1037948 </para>
/// </summary>
public class Perf : Dictionary<string, Action<int>> {}
 
/// <summary>Silly convenience initializer for creating Vs tasks with a dictionary that can also provides some output;
/// can use <code>new Perf&lt;T&gt; { { "task1", n => whatever }, {"task2", n => bar}...}</code>
/// <para>see http://stackoverflow.com/a/14000325/1037948 </para>
/// <example><code>
/// var p = new Perf{string} {
/// { "int", n => i.GetType().Name },
/// { "double", n => d.GetType().Name },
/// { "string", n => s.GetType().Name },
/// { "object", n => o.GetType().Name },
/// { "struct", n => t.GetType().Name },
/// { "anon", n => a.GetType().Name },
/// }.Vs("gettype");
/// </code></example>
/// </summary>
public class Perf<T> : Dictionary<string, Func<int, T>> {}
 
/// <summary>The actual extensions</summary>
public static class MyExtensions {
 
// Write custom extension methods here. They will be available to all queries.
 
#region ------------- pretty printing -----------------
private const char TITLE_UNDERLINE = '-';
public static void Title(this string msg, char underline = TITLE_UNDERLINE, int pad = 4, char padding = ' ') {
new string(underline, msg.Length + pad*2).Dump(new string(padding, pad) + msg + new string(padding, pad));
}
 
public static void TitleFormat(this string msg, params object[] tokens) {
new string(TITLE_UNDERLINE, msg.Length).Dump(string.Format(msg, tokens));
}
 
public static void DumpFormat(this string msg, params object[] tokens) {
string.Format(msg, tokens).Dump();
}
 
public static void DumpTitle(string msg, char underline = TITLE_UNDERLINE, int pad = 4, char padding = ' ') {
msg.Title(underline, pad, padding);
}
// CSV readfile -- http://www.developertipoftheday.com/2012/10/read-csv-in-linqpad.html
#endregion ------------- pretty printing -----------------
 
 
/// <summary>Useful for enumerating all of the property-values of an object
/// where Dump instead gets the `ToString`; ex) new Uri(...).Props()
/// </summary>
public static Dictionary<string, object> Props(this object me) {
return me.GetType().GetProperties().Where(o => o.CanRead).ToDictionary(o => o.Name, o => o.GetValue(me));
}
/// <summary>Useful for enumerating all of the property-values of an object
/// where Dump instead gets the `ToString`; ex) new Uri(...).RawDump()
/// </summary>
public static void RawDump(this object me, string title = null) {
me.Props().Dump(title);
}
#region ------------- benchmarking -----------------
 
/// <summary> Performance check -- how long do X repetitions of a task take?</summary>
public static TimeSpan Perf(this string reportTitle, Action<int> task, int repetitions = 10000, bool noShow = false) {
// http://stackoverflow.com/questions/28637/is-datetime-now-the-best-way-to-measure-a-functions-performance
Stopwatch sw = Stopwatch.StartNew();
 
for (int i = 0; i < repetitions; i++) {
task(i);
}
 
sw.Stop();
if( !noShow ) perfElapsed(sw.Elapsed).Dump(string.IsNullOrEmpty(reportTitle) ? null : string.Format("{0} ({1}x)", reportTitle, repetitions));
return sw.Elapsed;
}
private static string perfElapsed(TimeSpan ts) {
return string.Format("{0} ticks elapsed ({1} ms)", ts.Ticks, ts.TotalMilliseconds);
}
private static int indexOfMost<T>(IEnumerable<T> list, Func<T, T, bool> compare) {
int i = 0, j = 0;
T min = list.First();
foreach(var s in list) {
if(compare(min, s)) {
min = s;
j = i;
}
i++;
}
return j;
}
/// <summary> Performance check -- how long do 10K repetitions of the listed tasks take? Can also print the results of each task.
/// <example><code>
/// var p = new Perf{string} {
/// { "int", n => i.GetType().Name },
/// { "double", n => d.GetType().Name },
/// { "string", n => s.GetType().Name },
/// { "object", n => o.GetType().Name },
/// { "struct", n => t.GetType().Name },
/// { "anon", n => a.GetType().Name },
/// }.Vs("gettype");
/// </code></example>
/// </summary>
public static TimeSpan[] Vs<T>(this Dictionary<string, Func<int,T>> tasks, string reportTitle = null, int repetitions = 10000, bool noShow = false, bool run = true) {
if(run) tasks.Do().Dump("Output" + (reportTitle == null ? null : " for " + reportTitle));
return tasks.ToDictionary(k => k.Key, v => { Action<int> a = n => v.Value(n); return a; }).Vs(reportTitle, repetitions, noShow);
}
 
/// <summary> Performance check -- how long do 10K repetitions of the listed tasks take?</summary>
public static TimeSpan[] Vs(this Dictionary<string, Action<int>> tasks, string reportTitle = null, int repetitions = 10000, bool noShow = false) {
// tasks.Dump();
var n = tasks.Count();
var r = new Dictionary<string, TimeSpan>();
foreach (var task in tasks)
{
r.Add(task.Key, string.Empty.Perf(task.Value, repetitions, true));
}
 
if (!noShow)
{
reportTitle = (reportTitle ?? "Vs") + ": (" + string.Join(") vs (", tasks.Keys) + ")";
 
// get the best
var minIndex = indexOfMost(r, (a, b) => a.Value > b.Value);
 
r.ToDictionary(kv => kv.Key, kv => perfElapsed(kv.Value))
// r.Select(ts => perfElapsed(ts)).Concat(new[] { "winner: " + (hasSubs ? subReportTitles.ElementAt(minIndex) : minIndex + "th") })
/*
Tuple.Create(
r.Select(ts => perfElapsed(ts))
, "winner: " + (hasSubs ? subReportTitles.ElementAt(minIndex) : minIndex + "th")
)
*/
.Dump(reportTitle);
 
(">> winner: " + tasks.Keys.ElementAt(minIndex)).Dump();
}
 
return r.Select(kv => kv.Value).ToArray();
}
/// <summary> Performance check -- how long do X repetitions of the listed tasks take?</summary>
public static TimeSpan[] Vs(this string reportTitle, IEnumerable<string> subReportTitles, int repetitions, bool noShow, params Action<int>[] tasks) {
return Vs(Enumerable.Range(0, tasks.Length).ToDictionary(i => null == subReportTitles || subReportTitles.Count() <= i ? i.ToString() : subReportTitles.ElementAt(i), i => tasks[i])
, reportTitle, repetitions, noShow);
}
/// <summary> Performance check -- how long do 10K repetitions of the listed tasks take?</summary>
public static TimeSpan[] Vs(this string reportTitle, IEnumerable<string> reportTitles, params Action<int>[] tasks) {
return reportTitle.Vs(reportTitles, 10000, false, tasks);
}
/// <summary> Performance check -- how long do 10K repetitions of the listed tasks take?</summary>
public static TimeSpan[] Vs(this string reportTitle, params Action<int>[] tasks) {
return reportTitle.Vs(null, tasks);
}
public static void Do(this Dictionary<string, Action<int>> tasks) {
foreach(var kv in tasks) {
kv.Value(1);
}
}
/// <summary>Helpers for evaluating Perf</summary>
public static Dictionary<string,T> Do<T>(this Dictionary<string, Func<int,T>> tasks) {
return tasks.ToDictionary(kv => kv.Key, kv => kv.Value(1));
}
/// <summary>
/// Turn an anonymous object into a Dictionary; internally similar to System.Web.Mvc.HtmlHelper.AnonymousObjectToHtmlAttributes
/// </summary>
/// <remarks>http://aspnetwebstack.codeplex.com/SourceControl/changeset/view/5ac8586b78b3#src%2fSystem.Web.Mvc%2fHtmlHelper.cs</remarks>
/// <param name="collection">the anonymous collection of property-values</param>
/// <param name="explicitChangeType">flag whether or not to assume type conversion can occur automatically (false), or if we have to explicitly change the type (true)</param>
/// <returns>A typecast dictionary from the object</returns>
public static IDictionary<string, Tvalue> AnonymousObjectToDictionary<Tvalue>(this object collection, bool explicitChangeType = false) {
if (collection != null) {
// using manual property getter via http://weblogs.asp.net/leftslipper/archive/2007/09/24/using-c-3-0-anonymous-types-as-dictionaries.aspx
/*
return GetProperties(collection).ToDictionary(p => p.Name, p =>
(Tvalue)(implicitConvert ? Convert.ChangeType(p.Value, typeof(Tvalue)) : p.Value));
*/
 
// the following seems to throw up on some dictionaries when it encounters EqualityComparator properties???
return collection.GetType()
.GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public) // ignore "intrinsic" properties, like EqualityComparer, etc
.ToDictionary(p => p.Name, p => {
if (explicitChangeType) {
return (Tvalue)Convert.ChangeType(p.GetValue(collection, null), typeof(Tvalue));
}
else {
return (Tvalue)p.GetValue(collection, null);
}
});
/* */
}
 
return new Dictionary<string, Tvalue>();
}
 
 
#endregion ------------- benchmarking -----------------
 
#region ---------- JSON Extensions ----------
// http://geekswithblogs.net/EltonStoneman/archive/2012/05/11/extension-method-for-outputting-formatted-json-in-linqpad.aspx
public static object DumpJson(this object value, string description = null) {
return GetJsonDumpTarget(value).Dump(description);
}
 
public static object DumpJson(this object value, string description, int depth) {
return GetJsonDumpTarget(value).Dump(description, depth);
}
 
public static object DumpJson(this object value, string description, bool toDataGrid) {
return GetJsonDumpTarget(value).Dump(description, toDataGrid);
}
 
private static object GetJsonDumpTarget(object value) {
object dumpTarget = value;
//if this is a string that contains a JSON object, do a round-trip serialization to format it:
var stringValue = value as string;
if (stringValue != null) {
if (stringValue.Trim().StartsWith("{")) {
var obj = JsonConvert.DeserializeObject(stringValue);
dumpTarget = JsonConvert.SerializeObject(obj, Newtonsoft.Json.Formatting.Indented);
}
else {
dumpTarget = stringValue;
}
}
else {
dumpTarget = JsonConvert.SerializeObject(value, Newtonsoft.Json.Formatting.Indented);
}
return dumpTarget;
}
#endregion ---------- JSON Extensions ----------
}
z-includes.txt
1
Newtonsoft.Json.dll (only for the json dump extensions)
z-uses.cs
C#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
void Main()
{
// Write code to test your extensions here. Press F5 to compile and run.
"Test Default Underline".Title();
"Short".Title();
"Really Really Really Long Line that should probabbly never happen".Title();
"Alternate underline 1".Title('=');
"Alternate underline 2".Title('*');
"Alternate underline 3".Title('_');
MyExtensions.DumpTitle("stuff", '8');
"Testing Format Dump: {0} is the {1} in the {2}. {0}.".DumpFormat("A", "B", "C");
"Testing Format Dump: {0} is the {1} in the {2}. {0}.".TitleFormat("A", "B", "C");
var perfResult = "Perf test 1".Perf((i) => { i++; }, 100);
perfResult.Dump("Performance result");
#region ----------- testing VS usage styles ----------------
var s = "<?xml blah ?>things to live by";
var f = "?>";
/* bah!
var tests = new {
normal = n => s.IndexOf(f),
ordinal = n => s.IndexOf(f, StringComparison.Ordinal),
ordinalIgnore = n => s.IndexOf(f, StringComparison.OrdinalIgnoreCase)
};
*/
// this syntax sucks, needed `AnonymousTypeToDictionary` and then wasn't all that concise
// and i only got it to work once?
/*
var tasks = new {
normal = (Action<int>)( n => s.IndexOf(f) ),
ordinal = (Action<int>)( n => s.IndexOf(f, StringComparison.Ordinal) ),
ordinalIgnore = (Action<int>)( n => s.IndexOf(f, StringComparison.OrdinalIgnoreCase) )
}; tasks.Vs("comparisons");
*/
new Dictionary<string, Action<int>> {
{ "normal", n => s.IndexOf(f) },
{ "ordinal", n => s.IndexOf(f, StringComparison.Ordinal) },
{ "ordinalIgnore", n => s.IndexOf(f, StringComparison.OrdinalIgnoreCase) }
}.Vs("comparisons");
// equivalent to `new Dictionary<string, Action<int>> ...`
new Perf {
{ "normal", n => s.IndexOf(f) },
{ "ordinal", n => s.IndexOf(f, StringComparison.Ordinal) },
{ "ordinalIgnore", n => s.IndexOf(f, StringComparison.OrdinalIgnoreCase) }
}.Vs();
"comparisons".Vs(
n => s.IndexOf(f)
, n => s.IndexOf(f, StringComparison.Ordinal)
, n => s.IndexOf(f, StringComparison.OrdinalIgnoreCase)
);
"comparisons".Vs(new[] { "normal", "ordinal", "ordinalIgnore" }
, n => s.IndexOf(f)
, n => s.IndexOf(f, StringComparison.Ordinal)
, n => s.IndexOf(f, StringComparison.OrdinalIgnoreCase)
);
"comparisons".Vs(new[] { "normal" }, n => s.IndexOf(f), n => s.IndexOf(f, StringComparison.Ordinal), n => s.IndexOf(f, StringComparison.OrdinalIgnoreCase));
new Perf<DateTime> {
{ ".Now", n => DateTime.Now },
{ ".UtcNow", n => DateTime.UtcNow }
}.Vs("Datetime Fn");
#endregion ----------- testing VS usage styles ----------------
}//--- fn Main

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.