Skip to content

@zaus /LinqPad.MyExtensions.cs
Last active

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Linqpad Extensions - `.Title()`, `.DumpFormat(tokens)`, `.Perf(task)`, `.Vs(tasks)`
/// <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 ----------
}
Newtonsoft.Json.dll (only for the json dump extensions)
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.