If IT had been resposible for the creation of the world
Really funny read. Check it out here.
All the (developer) news that's unfit to read...
Really funny read. Check it out here.
Posted by IDisposable at 8/23/2006 04:35:00 PM 0 comments
Labels: fun
In this post comment, I was asked about how to do creation of method delegates whose types can vary somewhat when using the Dynamic
class. It's really a matter of using the unspecified form of a generic class and the Type.MakeGenericType
method to synthesize up the desired fully specified type. This code is going to look ugly, simply because playing with generics this way is more akin to writing a compiler than writing normal code. Much of this code is boiler-plate and could easily be extracted into a set of helper methods... given some time, I'll do so in my current Dynamic
class. Until then, here's an example of what things can look like:
// needed by both versions BindingFlags creatorFlags = BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Static; Type staticProc = typeof(Dynamic<>.Static.Procedure.Explicit<,,>); // this version "knows" the final argument type of the method, and could have been done explicitly // I show this to make obvious the way you use MakeGenericType. Type doubleProc = staticProc.MakeGenericType(typeof(PutMethods), typeof(IIdentifiable), typeof(string), typeof(double)); MethodInfo doubleProcCreateDelegate = doubleProc.GetMethod("CreateDelegate", creatorFlags, null, new Type[] { typeof(string) }, null); StaticProc<PutMethods, IIdentifiable, string, double> proc = doubleProcCreateDelegate.Invoke(null, new object[] { "Add" }) as StaticProc<PutMethods, IIdentifiable, string, double> proc(null, "Age", 1.0); // this is more like a normal use, where the final argument type is not known at delegate generation time... Type lazyProc = staticProc.MakeGenericType(typeof(PutMethods), typeof(IIdentifiable), typeof(string), typeof(object)); MethodInfo lazyProcCreateDelegate = lazyProc.GetMethod("CreateDelegate", creatorFlags, null, new Type[] { typeof(string) }, null); StaticProc<PutMethods, IIdentifiable, string, object> lazy = lazyProcCreateDelegate.Invoke(null, new object[] { "Add" }) as StaticProc<PutMethods, IIdentifiable, string, object> lazy(null, "Balance", -10.0); public interface IIdentifiable { void SetProperty(string propertyName, object value); } public class PutMethods { public static void Add(IIdentifiable dr, string propertyName, double value) { if (dr != null) dr.SetProperty(propertyName, value); } }
Note that you can easily build up the Type[]
passed to Type.MakeGenericType
based on things like an attribute class or configuration/XML markup.
Posted by IDisposable at 8/18/2006 04:23:00 PM 1 comments
Labels: .Net, C#, Dynamic, DynamicMethod, IL, LCG, lightweight code generation, MethodInfo
Looks like Google is finally going to update Blog*Spot (a.k.a. Blogger in hosted mode). Coming soon:
I'm waiting anxiously to migrate this blog there and start tagging labelling things.
More information here.
Posted by IDisposable at 8/15/2006 06:24:00 PM 0 comments
I've used "Send to Blogger...", I've used "w:Blogger", so why not try Microsoft's latest stab at Googledom? Looks neat so far. You can get more information over at Introducing Windows Live Writer
Posted by IDisposable at 8/14/2006 06:22:00 PM 0 comments
Ahhh, the warm feelings of nostalgia wave over me... in less than a month, I get to see if the sweet memory is a suite reality. Check out the New Turbo C++/Turbo Delphi/Turbo C# homepage.
Posted by IDisposable at 8/08/2006 11:40:00 PM 0 comments
Jeremy D. Miller recapitulates the Best of the Shade Tree Developer. I nominate this as the most useful post of the year.
Posted by IDisposable at 8/08/2006 04:22:00 PM 0 comments
The new declarative model for data sources in ASP.Net 2.0 is very seductive in its simplicity. I've all-too-often seen people doing date-picker and time-pickers by listing the times individually in ListItem
s. This leads to pages that have to be manually revisited if you change the range (start-time and end-time) or the increment (e.g. on-the-hour, on-the-half, etc.). It would be really cool to be able to drive these lists declaratively and bind them using the standard DataSourceID
logic.
Using the new C# yield
keyword it is trivial to return an IEnumerable<DateTime>
that lists all the times (with a specified increment in minutes), days, weeks, months, etc. in a date range. I give you DateTimeDataSource:
using System; using System.Collections.Generic; using System.ComponentModel; [DataObject(true)] public class DateTimeDataSource { private TimeSpan _DayStart = TimeSpan.FromHours(8); // default to 8am private TimeSpan _DayEnd = TimeSpan.FromHours(18); // default to 6pm [Browsable(true)] public TimeSpan DayStart { get { return _DayStart; } set { _DayStart = value; } } [Browsable(true)] public TimeSpan DayEnd { get { return _DayEnd; } set { _DayEnd = value; } } public static DateTime WeekStart(DateTime date) { return date.Date.AddDays(-(int)date.DayOfWeek); } public static DateTime WeekEnd(DateTime date) { return date.Date.AddDays(7).AddTicks(-1); } public static DateTime MonthStart(DateTime date) { return date.Date.AddDays(1 - date.Day); } public static DateTime MonthEnd(DateTime date) { return date.Date.AddMonths(1).AddTicks(-1); } public static DateTime YearStart(DateTime date) { return new DateTime(date.Year, 1, 1); } public static DateTime YearEnd(DateTime date) { return new DateTime(date.Year + 1, 1, 1).AddTicks(-1); } [DataObjectMethod(DataObjectMethodType.Select, true)] public IEnumerable<DateTime> ThisWeek() { DateTime start = WeekStart(DateTime.Today); DateTime end = WeekEnd(start); return Any(start, end, TimeSpan.FromDays(1)); } [DataObjectMethod(DataObjectMethodType.Select, true)] public IEnumerable<DateTime> ThisMonth() { DateTime start = MonthStart(DateTime.Today); DateTime end = MonthEnd(start); return Any(start, end, TimeSpan.FromDays(1)); } [DataObjectMethod(DataObjectMethodType.Select, true)] public IEnumerable<DateTime> Today(int minuteIncrement) { return Any(DateTime.MinValue, DateTime.MaxValue, minuteIncrement); } [DataObjectMethod(DataObjectMethodType.Select, false)] public IEnumerable<DateTime> Today(TimeSpan increment) { return Any(DateTime.MinValue, DateTime.MaxValue, increment); } [DataObjectMethod(DataObjectMethodType.Select, true)] public IEnumerable<DateTime> Weeks(int numberOfWeeks) { DateTime start = WeekStart(DateTime.Today); DateTime end = start + TimeSpan.FromDays(7 * numberOfWeeks); return Weeks(start, end); } [DataObjectMethod(DataObjectMethodType.Select, false)] public IEnumerable<DateTime> Weeks(DateTime start, int numberOfWeeks) { DateTime end = start + TimeSpan.FromDays(7 * numberOfWeeks); return Weeks(start, end); } [DataObjectMethod(DataObjectMethodType.Select, false)] public IEnumerable<DateTime> Weeks(DateTime start, DateTime end) { return Any(start, end, TimeSpan.FromDays(7)); } [DataObjectMethod(DataObjectMethodType.Select, true)] public IEnumerable<DateTime> Any(DateTime start, DateTime end, int minuteIncrement) { return Any(start, end, TimeSpan.FromMinutes(minuteIncrement)); } [DataObjectMethod(DataObjectMethodType.Select, false)] public IEnumerable<DateTime> Any(DateTime start, DateTime end, TimeSpan increment) { if (start == DateTime.MinValue || start.Ticks == 0) { start = DateTime.Today.Date + DayStart; } if (end == DateTime.MaxValue || end.Ticks == 0) { end = DateTime.Today.Date + DayEnd; } for (DateTime current = start; current <= end; current += increment) { yield return current; } } }
Use this just like you would any other data source, for example, to build a RadioButtonList
for the normal working hours (8am to 6pm, see notes below), you can do this:
<asp:ObjectDataSource ID="Hours" runat="server" CacheDuration="Infinite" EnableCaching="true" TypeName="DateTimeDataSource" SelectMethod="Today"> <SelectParameters> <asp:Parameter Name="minuteIncrement" Type="Int32" Direction="Input" DefaultValue="30" /> </SelectParameters> </asp:ObjectDataSource> <asp:RadioButtonList ID="RadioButtonTimeFrom" runat="server" DataSourceID="Hours" DataTextFormatString="{0:t}" />
DayStart
and DayEnd
let you change the default start and end time for time-pickers.UPDATE: Blogger ate my || in the code of Any
Posted by IDisposable at 8/02/2006 03:13:00 PM 1 comments
Labels: .Net, Asp.Net, C#, DataSource, DateTime
Dear Microsoft Live.com team, Please stop assigning new link value to all the posts when you upgrade the software on Live.com. I really hate having to prune all the duplicates out of my RSS reader. Permalinks are supposed to be permanent, not "valid until further upgrades". Thank you and enjoy your day, Marc
Posted by IDisposable at 8/02/2006 12:05:00 PM 0 comments
Labels: Annoyances, RSS