Friday, April 18, 2008
Blogger & HTML
Generic Gripes
Two things:
1. If you have a generic class with type parameter constraints, those contraints are not inherited automatically in sub types. Ex:
class Foo<T> where T: IConvertible
{
}
class Bar<T> : Foo
{
}
Don't work. You have to put the "where T: IConvertible" on Bar. Doesn't make sense to me.
2. There is no way to loop through a bunch of generic instances with different type parameters and access members that don't have type parameters anywhere in their signature. Ex:
If you have some lists, like:
List<int> = GetInts();
List<strings> = GetStrings();
You can't reference them with just List<> or List<?> or something. While obviously
you can't access the Add, Insert, indexer, and whatever else has the generic type in it. But it would be really convenient if I could access things that don't use it, like Count.
It would be cool to be able to do something like this:
using the two lists above:
List<List<?>> lists = List<List<?>> (ints, strings);
foreach( List<?> currList in lists )
{
int count = currList.Count;//Add would not be available. But Clear would.
}
In the List case, IList makes it possible to loop through some lists and get the Count. So maybe that's a bad example. But imagine you make your own sweet generic class, and want to access some generic-agnostic member, like the HasValue property of Nullable<T>. Then you have to implement an interface or derive from a base class that isn't generic.
I understand why that's not possible today and that it would be difficult to allow. However, it's not impossible and would be nice.
That's all. Very granular crap. Nice weather today.
Friday, April 11, 2008
Download HTTP Resource Without Browser
In the meantime, I wrote a small console app that downloads some url and saves it to a local file. It's only a few lines. Create a new console app and use the following code:
class Program
{
static void Main(string[] args)
{
string uri = args[0];
string filePath = args[1];
byte[] bytes = (new WebClient()).DownloadData(args[0]);
File.WriteAllBytes(filePath, bytes);
}
}
That's it. Using that I was able to get my xaml. Gotta love that .net framework!
Friday, April 4, 2008
Unneccessay EventArgs
I'm sure you all would agree that the unnecessary creation of objects is not good. Wasting is something we should try to avoid. For example, wouldn't it strike you as wrong to create EventArgs objects for events that are never raised?
Take this code, which is a basic event to alert the application code when a user signs in. The event args gives the developer some more info about the user who logged in:
internal class SigninManager
{
public event EventHandler<SignedInEventArgs> SignedIn;
protected virtual void OnSignedIn(SignedInEventArgs e)
{
if (SignedIn != null)
SignedIn(this, e);
}
private void PerformSignIn()
{
//work work work
string userName = "blah";
//work work work
SignedInEventArgs args = new SignedInEventArgs() { UserName = userName };
OnSignedIn(args);
}
}
public class SignedInEventArgs: EventArgs
{
public string UserName { get; internal set; }
}
Note I'm using some C# 3 features, but this could be done with a prior version with not much work.
In OnSignedIn, you'll notice the event will never get invoked if Fooing is null. The event is only for informational purposes to outside code. If I wanted some feedback, such as a Handled property, things might be different. But I just want to tell application code that "hey, this person logged in."
If no outside code ever handles SignedIn, I am creating the SignedInEventArgs without ever using it. What I would prefer is that the event args get created only if they are needed. But I want to keep my code pretty much the same. I want to keep my OnSignedIn there so I can override it in a sub class. And I don't want to fool with event logic in PerformSignIn. What I need is "lazy instantiation", where the event args only get created if needed.
While there are several approaches, I have a pretty elegant one: use delegates. I will use lamda expressions in my code, although anonymous delegates would work fine. Check this out:
public delegate TEventArgs EventHandlerCreator<TEventArgs>();
internal class SigninManager
{
public event EventHandler<SignedInEventArgs> SignedIn;
protected virtual void OnSignedIn(EventHandlerCreator<SignedInEventArgs> argsDelegate)
{
if (SignedIn != null)
{
SignedIn(this, argsDelegate());
}
}
private void PerformSignIn()
{
//work work work
string userName = "blah";
//work work work
OnSignedIn( () => new SignedInEventArgs() { UserName = userName } );
}
}
public class SignedInEventArgs: EventArgs
{
public string UserName { get; internal set; }
}
Now, instead of passing the event args object I created, I pass a delegate that's able to create the args when invoked. So the OnSigningIn takes that delegate and only creates the args if the event is handled. If it is invoked a million times, we've saved a million objects :).
I think the code is pretty straightforward. Lamda expressions and generics make "lazy instantiation" something that's practical to acheive and maintain. Again, this could be applied to different, more meaningful situations. Regardless, it's pretty nice.
Friday, March 14, 2008
Converting Arrays to and from Delimited Strings
Maybe the reason it's not there is because delimited strings can be error-prone, and serialization mechanisms support arrays. But let's forget about why, because sometimes you need to do this.
I write a few simple, yet flexible methods for accomplishing this. I used arrays, although another version of the methods could be created for IEnumerables or ICollections or whatever. For my situation, I needed only arrays so I looked past my abstraction apprehensions and just did it.
One interesting thing was that in certain situations I needed custom code to convert each item to and from its string. So my methods allow for that using a delegate. And to accomodate for all array types and for type safety, I used generic methods. So this is a cute way to blend those two features that have been around since C# 2.0.
/// <summary>
/// Takes a delimited string and returns an array of items that were converted to the type specified. Individual value conversions
/// are done by using the type converter ConvertFromInvariantString method.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <param name="separator"></param>
/// <returns></returns>
public static T[] ConvertDelimitedStringToArray<T>(string value, string separator)
{
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
Func<T, string> itemConversionHandler = delegate(string itemText)
{
return (T)converter.ConvertFromInvariantString(itemText);
};
return ConvertDelimitedStringToArray(value, separator, itemConversionHandler);
}
/// <summary>
/// Takes a delimited string and returns an array of items that were converted to the type specified.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <param name="separator"></param>
/// <param name="itemConversionHandler">The delegate that converts each string item into the target type.</param>
/// <returns></returns>
public static T[] ConvertDelimitedStringToArray<T>(string value, string separator, Func<T,string> itemConversionHandler)
{
if (string.IsNullOrEmpty(value))
return null;
string[] pieces = value.Split(new string[]{separator},StringSplitOptions.None);
T[] result = new T[pieces.Length];
for (int i = 0; i < pieces.Length; i++)
{
result[i] = itemConversionHandler(pieces[i]);
}
return result;
}
/// <summary>
/// Takes an array of items and converts it to a delimited string with the separator. Individual value conversions
/// are done by using the type converter ConvertToInvariantString method.
/// </summary>
public static string ConvertArrayToDelimitedString<T>(T[] value, string separator)
{
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
Func<string, T> itemConversionHandler = delegate(T item)
{
return converter.ConvertToInvariantString(item);
};
return ConvertArrayToDelimitedString(value, separator, itemConversionHandler);
}
/// <summary>
/// Takes an array of items and converts it to a delimited string with the separator and conversion handler provided.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <param name="separator"></param>
/// <param name="itemConversionHandler">The delegate that converts each item into a piece of text.</param>
/// <returns></returns>
public static string ConvertArrayToDelimitedString<T>(T[] value, string separator, Func<string,T> itemConversionHandler)
{
if (value == null || value.Length == 0)
return null;
string[] textPieces = new string[value.Length];
for (int i = 0; i < value.Length; i++)
{
textPieces[i] = itemConversionHandler(value[i]);
}
return string.Join(separator, textPieces);
}
If you have .NET 3.5 (I think), the Func delegate is already there. If not, you can just define it yourself:
/// <summary>
/// A delegate to a methd that returns some TReturn value and has 1 parameter.
/// </summary>
/// <typeparam name="TReturn">The type of object the method returns.</typeparam>
/// <typeparam name="TParam1">The type of the first method parameter.</typeparam>
/// <returns></returns>
internal delegate TReturn Func<TReturn, TParam1>(TParam1 param1);
That's all you need, really. To demonstrate, check out the code below:
//create some ints and make them pipe separated
int[] ids = new int[] { 1, 2, 3, 4 };
string delimitedList = ConvertArrayToDelimitedString<int>(ids, "|");
ids = ConvertDelimitedStringToArray(delimitedList, "|");//and back again
//now I take some dates and put only their day in a list
DateTime[] dates = new DateTime[] { DateTime.Parse("2/29/1980"), DateTime.Parse("3/1/1980"), DateTime.Parse("3/5/1998") };
//my own 'custom' (albeit useless) conversion code to convert each date to have its parts separated by -
delimitedList = ConvertArrayToDelimitedString<DateTime>(dates, "|",
delegate(DateTime item)
{
return item.ToString("MM-DD-YY");//forgive me if my format string is not right
}//note: I could have declared the delegate in a variable above, but kept it here to confuse people and hopefully make them think I am some kind of wizard (don't you love guys like that?)
);
Thursday, February 21, 2008
Convert percent string to double
double value = .45;
string formatted = value.ToString("p", CultureInfo.CurrentUICulture);
No big deal. Comes out as "45.00 %" for many cultures. It's similar for the others, which things like 4"5,00 % ". Always multiplies the number by 100. Easy.
But converting it back to a double isn't so easy. double.Parse and TryParse don't work with percentages. After looking on the web for a while, I didn't find a good solution. I needed it to work for all cultures and be pretty forgiving in the input it allowed. So here's my solution:
static double ConvertPercentageToDouble(string formattedNumber)
{
return ConvertPercentageToDouble(formattedNumber,CultureInfo.CurrentCulture);
}
static double ConvertPercentageToDouble(string formattedNumber, System.Globalization.CultureInfo cultureInfo)
{
if (string.IsNullOrEmpty(formattedNumber))
throw new ArgumentNullException("formattedNumber");
formattedNumber = formattedNumber.Replace(cultureInfo.NumberFormat.PercentSymbol, string.Empty);
double value = double.Parse(formattedNumber, NumberStyles.Any, cultureInfo);
if (value != 0)
value /= 100.0;
return value;
}
Monday, January 28, 2008
South Florida Code Camp
http://codecamp08.fladotnet.com/
Check out the agenda for a list of the various tasty talks.