Cool stuff in FubuCore No. 2: Extension Methods
This is the second post of the FubuCore series mentioned in the Introduction post.
This post covers the various and plentiful extension methods contained in the FubuCore project. We have built up these extensions methods over the last 3-4 years in anger. Some of them may be a little sloppy and not up to your liking or taste level, but all of them are used heavily and have been running in multiple production systems for quite a while (some of them over 2 years). We find most of them to be invaluable and use them every day. I hope you find some value in them as well.
IfNotNull
Various overloads (Source)
This one is super handy. How many times have you written code like this?
if( value != null ) { doSomething(); }
Well, it really stinks when you’re in the middle of a code flow and you need to do something only if “value” is not null. Well, now you can do stuff like this:
var name = employee.IfNotNull(e => e.FullName); // or employee.IfNotNull(e => doSomething(e));
Hiding Data In Views With If/IfNot
(Source)
With Fubu authorization, you can hide pieces of information in the view if the current ser doesn’t have access to it. We wrote short-hand methods to assist us with this in the view. Assume the view’s model has a property called “CanSeeSalaryInformation” which represents the result of an authorization check for a user permission.
<span><%= employee.Salary.If(()=> Model.CanSeeSalaryInformation)%></span>
Making Dictionary.Get Not As Annoying
Various overloads (Source)
If you do manage to find yourself using a Dictionary instead of a Cache, you can get around some of the pain of having to do the “ContainsKeys” checks by using the Get extension methods. A lot of times you want to get a value from a dictionary but don’t want to do all the “ContainsKey” checking or messing with the “out” variable in the “TryGetValue” method.
Let’s say you want to get the value of a key from a dictionary which may not be there. And if it’s not there, then return a default value (let’s say, empty string).
dictionary.Get("mykey", "");
Enumerable Extensions
(Source)
Like most programmers, we do a lot of stuff with enumerables (lists, arrays, and other fun list-y type structures). So we’ve evolved a lot of enhancements and extensions to make them easier to use in various situation.
IList Extensions
Fill(T value): Add an item to a list if it isn’t already in the list.
RemoveAll(Func<T, bool> whereEvaluator): Removes items from the list that match the function/predicate.
**AddRange(IEnumerable
AddMany(params T[] items): Just like AddRange, but allows for many param arguments as well as method chaining.
IEnumerable Extensions
**Each(Action
FirstValue(Func<T, UReturn> returnFunc): Kinda like FirstOrDefault, but more like combining a Where and a Select and a FirstOrDefault in one method. This method will iterate over the enumerable, executing your returnFunc until it gets a non-null result. If none was found, it just returns null.
**IsEqualTo(IEnumerable
String Extensions
Join(string separator): Just like String.Join except it allows method chaining.
Stream Extensions
(Source)
ReadAllText: This does the tedium of new()’ing up a StreamReader and calling ReadToEnd. It saves a few lines of code when all you want to do is open a stream and read the whole thing in. I think we use this for reading text embedded assembly resources If you’re working with files, it’s better to just call File.ReadAllText.
String Extensions
(Source)
CombineToPath(string root): If the path is rooted, just returns the path. Otherwise, this combines the root and path. (Uses Path.IsPathRooted and Path.Combine)
ToFullPath(): Just like Path.GetFullPath, but allows method chaining.
AppendPath(params string[] paths): Repeatedly calls Path.Combine on a list of paths (i.e. /bar/baz/zab/rab).
PathRelativeTo(string root): Makes the current string (assumed to be a path) rooted against the specified root. (i.e. “/bar/baz”.PathRelativeTo(“c:”) will result in “c:/bar/baz”).
IsEmpty(): Same as String.IsNullOrEmpty, but hangs off the string itself as an extension method.
IsNotEmpty(): Opposite of IsEmpty.
**IsNotEmpty(Action
ToBool: Converts a string to boolean. It handles the null/empty check, and then calls Bool.Parse.
ToFormat: (My personal favorite) Calls String.Format, but allows for method chaining. Example:
return "You have {0} turns remaining.".ToFormat(numTurnsLeft);
EqualsIgnoreCase(string otherString): Calls String.Equals with StringComparison.InvariantCultureIgnoreCase.
Capitalize: A more convenient way to call: CultureInfo.CurrentCulture.TextInfo.ToTitleCase(value)
HtmlAttributeEncode, HtmlEncode, HtmlDecode, UrlEncode, UrlDecode: A more convenient way to call the corresponding methods on System.Web.HttpUtility.
ConvertCRLFToBreaks(string plainText): Converts “\r\n” or “\n” to “
” (handy for html-izing some plain text”).
ToDateTime(string dateTimeValue): A more convenient way of calling DateTime.Parse.
ToGmtFormattedDate: Prints out a log-file friendly date/time stamp in full format in the GMT timezone (i.e. “yyyy-MM-dd hh:mm:ss tt GMT”).
ToDelimitedArray: A more convenient way of calling String.Split, plus it strips away extra whitespace so “a “,”b”, and ” c” get turned into “a,b,c”.
IsValidNumber: Uses regex to attempt to determine if the string contains something recognizable as a number. If memory serves, this was written in anger at Decimal.Parse which never seemed forgiving enough and would frequently miss values that were clearly (to humans) numbers.
getPathParts: Breaks down a string like “c:/bar/baz/zab” into a list of strings “c:”, “bar”, “baz”, and “zab”.
DirectoryPath: A more convenient way of calling Path.GetDirectoryName.
Type Extensions
(Source)
These are some *really* handy methods if you do a lot of work with generics, expression trees, or both.
Unfortunately, this blog post would be four times larger if I mentioned all the great extension methods. I strongly suggest you browse through this source file (linked above) because you will definitely find at least one thing that you can use.
I hand-picked a few ones that I thought were especially useful and might whet your appetite :
IsNullableOfT(): Determines if the given type implements Nullable<> or not (i.e. DateTime?).
IsNullableOf(Type otherType): Determines if the given type is a Nullable
**IsTypeOrNullableOf
**CanBeCastTo
IsConcreteWithDefaultCtor: Determines if this type is a concrete type with a default/open constructor (i.e. you could call Activator.CreateInstance() on it with no exceptions).