JavaScript: to prototype or not?

A recurring topic of some discussion among JavaScript users is whether to use prototype or instance/constructor-inner methods when defining JavaScript objects.

Prototype methods can be incredibly useful, but are in essence much like C# extension methods (which are incredibly useful for similar reasons). The primary use of both is to add functionality to a class/object type over which one does not have control. In this way, both C# extension methods and JavaScript prototype methods can even add functionality to foundational platform types in each language or environment. (Proponents of using prototype methods for everything sometimes point out that there is a small memory-use difference between prototype and non-prototype functions, but that difference is completely negligible for client-side development.)

Methods defined inside an object constructor, directly on “this”, have a major advantage in correct object-oriented design, however. That’s because methods inside the constructor can also access private properties/variables defined inside the constructor. Prototype methods cannot do this, as this example clearly demonstrates. A minor additional benefit is that instance methods defined this way are contained inside the constructor, a more object-oriented style than the extension-method feel of prototype methods.

This difference means that constructor-inner methods are the only correct choice for constructing object-oriented JavaScript. The alternate, using prototype methods only, would be akin to designing a C# or Java class with no private fields or properties, a clear violation of the encapsulation principle.

It’s clear that at least for client-side development, prototype methods may be useful to decorate a pre-existing API–but when designing one’s own object-oriented JavaScript, there is only one appropriate choice.

Advertisements

Easily execute dynamic C# using extension methods

Code has now been released under the SharpByte project to execute dynamic C# scripts (and evaluate statements) more easily than ever before. Dynamic code execution during earlier days of .NET was a sore spot, with many lamenting the lack of a functional equivalent to the JavaScript eval() function. For years many developers attempted hacks like using ASP.NET’s DataBinder.Eval(), but results were often subpar and performance was lackluster. Compiling to the CodeDom and the newer .NET Compiler Platform, a.k.a. Roslyn, can be moderately simple to complex depending on need, but many developers just want a simple, easy-to-reuse solution for supporting dynamic code entry in an application.

Further documentation on the easy-to-use API will be forthcoming, but for now these steps will suffice for anyone wishing to play with the code:

1. Either build and reference the project’s core assembly in your project, or import the code directly into your project.

2. If the code was built with conditional compilation symbol GLOBAL_EXTENSIONS, all objects will be able to use the dynamic-execution extension methods. Otherwise, if COLOCATE_EXTENSIONS was used, add a using statement for the System.Runtime.CompilerServices namespace; if neither GLOBAL_EXTENSIONS nor COLOCATE_EXTENSIONS was used, add a using statement for the SharpByte.Dynamic namespace.

3. Call any version of .Execute() or .Evaluate() directly on any object. The former will execute any C#-compliant script composed of properly semicolon-terminated lines of code, with “this” references executed on the object on which the extension methods are called (i.e. the context object for the call); the latter will evaluate a C# expression and return the result.

Once these steps are done, calling a script is as easy as this:

someObject.Execute("[script statements go here, and may be many lines]");

To anyone curious enough to understand the working of these extension methods, the code will be illustrative. Essentially, the extension methods call into a facade for compilation features of the .NET framework, and can be used to front-end calls to the CodeDom, the .NET Compiler Platform (“Roslyn”), or any other compiler, vastly simplifying the most-needed dynamic code compilation and execution features of each.

Here’s an example of the relatively complex task of building code using the CodeDom (without any attempt to slam the useful-looking code at this page, just provide an example of the complexity hidden away). Roslyn provides many enhancements over CodeDom, but still to simply execute a script, such as user-entered code in a CMS or other data system, isn’t always completely simplified as it could be.

The provided reference code compiles code constructed on-the-fly using the referenced compiler. A code formatter emits source code, without needing any special knowledge of the underlying compiler. A quick review of the System.Object extension methods involved shows how easy it is to retain a reference to the compiled IExecutable instance as well, which can be used to inspect the built-in execution log and timings, as well as any exception generated by the last run of a compiled executable. A unique signature based on the executable code type (expression/statement or script), parameter names, and source code is used on subsequent calls to check for pre-existing compiled executables, stored in the ExecutableFactory hybrid factory/collection for reuse.

Each executable can be compiled successfully with numbered placeholder values, a la string.Format() (but using triple curly braces to avoid .NET and Handlebars-style format interference) and/or named parameter values. As mentioned above, the context object (when using extension methods, the object on which the method is called) is used for any references to “this” within any script or expression.

Since an object from each compiled executable type has a Copy() method, it can safely and cheaply be used to create further executables of the same type. Calling Execute() on any particular executable is guaranteed to be thread-safe due to use of synchronization; for that reason, it’s easiest to cache local copies of reusable expressions/scripts.

Performance-wise, on a fairly low-spec laptop, formatting source code for a new class tests in the 1-2 microsecond range; post-compilation, execution of a script or expression can take well under a microsecond (e.g. a two-parameter complex mathematical expression which tests in the 800-nanosecond range), depending of course on complexity. The bulk of this fairly small overhead is due to the use of dynamic variables within the compiled classes themselves. If warranted, type safety may be added to the context object and/or named parameters to boost peformance further.

This generic utility code was originally developed in support of the SharpByte CMS, but is provided separately under the MIT License. Happy coding!

Safely navigating object hierarchies in JavaScript using prototype methods

New: Dynamically evaluate C# expressions and execute C# scripts with a single statement, from anywhere in a .NET application. Click here for more info.

Anyone who’s dealt with a deeply nested set of properties in JavaScript, whether through use of an extensive third-party JavaScript API or a custom library, has likely run into the problem of safely accessing such structures. One can of course hand-roll many ugly, hard-to-read statements like the following, adding on to the maintenance burden of the code (splitting lines as necessary for length, of course):

if (a && a.b && a.b.c && a.b.c.d && a.b.c.d.e) { doSomethingWith(a.b.c.d.e); }

The main alternative to this approach is to make such accesses within a try-catch block, but this is generally slower by at least a couple of orders of magnitude when exceptions are thrown, so not always useful in tight loops and other performance-sensitive situations. It’s also arguably an abuse of the try/catch mechanism.

Luckily, a less unsavory solution with fairly good performance can be adopted using JavaScript prototype methods. Here’s a reference implementation, and you can also try it for yourself (with timings):

// Indicates whether an object has the indicated nested subproperty, which may be specified with chained dot notation 
// or as separate string arguments.
Object.prototype.hasSubproperty = function() {
	if (arguments.length == 0 || typeof(arguments[0]) != 'string') return false;  
  var properties = arguments[0].indexOf('.') > -1 ? arguments[0].split('.') : arguments;    
  var current = this;
  for(var x = 0; x  -1 ? arguments[0].split('.') : arguments;    
  var current = this;
  for(var x = 0; x < properties.length; x++) {
  	current = current[properties[x]];
    if ((typeof current) == 'undefined') return undefined;
  }  
  return current;
};

// Gets the indicated nested subproperty, which may be specified with chained dot notation or as separate arguments.
// If the specified subproperty (or any intervening object in the hierarchy) is not found, returns undefined.
Object.prototype.getSubproperty = function() {
	if (arguments.length == 0 || typeof(arguments[0]) != 'string') return false;  
  var properties = arguments[0].indexOf('.') > -1 ? arguments[0].split('.') : arguments;    
  var current = this;
  for(var x = 0; x < properties.length; x++) {
  	current = current[properties[x]];
    if ((typeof current) == 'undefined') return undefined;
  }  
  return current;
};

// Sets the indicated nested subproperty, which may be specified with chained dot notation or as separate arguments.
// If any intervening object in the hierarchy is not found, returns false, otherwise sets the value and returns true.
Object.prototype.setSubproperty = function() {
	if (arguments.length  -1 ? arguments[0].split('.') : Array.prototype.slice.call(arguments, 0, arguments.length - 1);    
  var parent, current = this;
  for(var x = 0; x < properties.length - 1; x++) {
  	current = current[properties[x]];
    if ((typeof current) == 'undefined') return false;
  }  
  current[properties[properties.length - 1]] = arguments[arguments.length - 1];
  return true;
};

Some observations: if you run the timings, you’ll note that the try-catch method is still quite fast when exceptions are not thrown, indicating that try-catch might be workable when exceptions are expected to be truly… exceptional. Still, in any but extraordinary conditions, the performance of the prototype-method approach should be quite fast enough, avoids worst-case performance, and is cleanest overall.

Some thoughts on global extension methods

New: Dynamically evaluate C# expressions and execute C# scripts with a single statement, from anywhere in a .NET application. Click here for more info.

In the past, I’ve sometimes found it useful to place some very generic extension methods in the global namespace, and/or at a visibility level corresponding to the classes extended. This can ease reuse, as the extension methods don’t require developers to take extra steps or have extra knowledge to use them; they’re just immediately available in type-ahead. Anyone who has suffered through using a namespace-happy API with multiple locations for extension methods may thank you for this approach.

As a brief example, consider the extension methods below. These mainly provide a bit of syntactic sugar for working with regular expressions, by converting what would often be multi-line calls into a single expression. The hiding of the System.Text.RegularExpressions namespace would be complete, except that in a few cases Match objects are exposed, as useful bundles of values and indices in the original string; System.Text.RegularExpressions would never need to be explicitly used even with those methods, if the var keyword were used.

using System.Collections.Generic;
using System.Text.RegularExpressions;

public static partial class StringExtensions
{
    private static MatchCollection EmptyMatchCollection = Regex.Matches("", "0");

    private static Match UnsuccessfulMatch = Regex.Match("a", "b");

    public static bool IsMatch(this string s, string pattern, bool isCompiled = false, bool ignoreCase = false)
    {
        if (s == null || pattern == null) return false;
        RegexOptions options = RegexOptions.CultureInvariant;
        if (ignoreCase)
            options |= RegexOptions.IgnoreCase;
        if (isCompiled)
            options |= RegexOptions.Compiled;
        return Regex.IsMatch(s, pattern, options);
    }

    public static int IndexOfPattern(this string s, string pattern, bool isCompiled = false, bool ignoreCase = false)
    {
        if (s == null || pattern == null) return -1;
        RegexOptions options = RegexOptions.CultureInvariant;
        if (ignoreCase)
            options |= RegexOptions.IgnoreCase;
        if (isCompiled)
            options |= RegexOptions.Compiled;
        Match match = Regex.Match(s, pattern, options);
        return match.Success ? match.Index : -1;
    }

    public static int LastIndexOfPattern(this string s, string pattern, bool isCompiled = false, bool ignoreCase = false)
    {
        if (s == null || pattern == null) return -1;
        RegexOptions options = RegexOptions.CultureInvariant | RegexOptions.RightToLeft;
        if (ignoreCase)
            options |= RegexOptions.IgnoreCase;
        if (isCompiled)
            options |= RegexOptions.Compiled;
        Match match = Regex.Match(s, pattern, options);
        return match.Success ? match.Index : -1;
    }

    public static MatchCollection Matches(this string s, string pattern, bool isCompiled = false, bool ignoreCase = false)
    {
        if (s == null || pattern == null) return EmptyMatchCollection;

        RegexOptions options = RegexOptions.CultureInvariant;
        if (ignoreCase)
            options |= RegexOptions.IgnoreCase;
        if (isCompiled)
            options |= RegexOptions.Compiled;

        return Regex.Matches(s, pattern, options);
    }

    public static IEnumerable FindAll(this string s, string pattern, bool isCompiled = false, bool ignoreCase = false)
    {
        if (s == null || pattern == null) return new List();

        RegexOptions options = RegexOptions.CultureInvariant;
        if (ignoreCase)
            options |= RegexOptions.IgnoreCase;
        if (isCompiled)
            options |= RegexOptions.Compiled;
        
        return Regex.Matches(s, pattern, options).Select(m => m.Value);
    }

    public static Match Match(this string s, string pattern, bool isCompiled = false, bool ignoreCase = false)
    {
        if (s == null || pattern == null) return UnsuccessfulMatch;

        RegexOptions options = RegexOptions.CultureInvariant;
        if (ignoreCase)
            options |= RegexOptions.IgnoreCase;
        if (isCompiled)
            options |= RegexOptions.Compiled;

        return Regex.Match(s, pattern, options);
    }

    public static Match MatchLast(this string s, string pattern, bool isCompiled = false, bool ignoreCase = false)
    {
        if (s == null || pattern == null) return UnsuccessfulMatch;

        RegexOptions options = RegexOptions.CultureInvariant | RegexOptions.RightToLeft;
        if (ignoreCase)
            options |= RegexOptions.IgnoreCase;
        if (isCompiled)
            options |= RegexOptions.Compiled;

        return Regex.Match(s, pattern, options);
    }

    public static string Find(this string s, string pattern, bool isCompiled = false, bool ignoreCase = false)
    {
        if (s == null || pattern == null) return "";

        RegexOptions options = RegexOptions.CultureInvariant;
        if (ignoreCase)
            options |= RegexOptions.IgnoreCase;
        if (isCompiled)
            options |= RegexOptions.Compiled;

        Match match = Regex.Match(s, pattern, options);
        return match.Success ? match.Value : "";
    }

    public static string FindLast(this string s, string pattern, bool isCompiled = false, bool ignoreCase = false)
    {
        if (s == null || pattern == null) return "";

        RegexOptions options = RegexOptions.CultureInvariant | RegexOptions.RightToLeft;
        if (ignoreCase)
            options |= RegexOptions.IgnoreCase;
        if (isCompiled)
            options |= RegexOptions.Compiled;
        Match match = Regex.Match(s, pattern, options);
        return match.Success ? match.Value : "";
    }

}

The MatchCollection class itself is kind of an odd duck, as it’s a useful collection that was never fully updated for use with Linq. If one makes frequent use of regular expressions it might be useful to also put a few simple Linq-enabling extension methods on MatchCollection itself; it’s up to the user whether to make them global. I leave it to the reader to implement the rest of the Linq methods as deemed useful in a particular case.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

public static partial class MatchCollectionExtensions
{
    public static bool Any(this MatchCollection source, Func<Match, bool> predicate)
    {
        return source.Cast<Match>().Any(predicate);
    }

    public static Match First(this MatchCollection source)
    {
        return (source == null || source.Count == 0) ? null : source[0];
    }

    public static Match First(this MatchCollection source, Func<Match, bool> predicate) {
        return source.Cast<Match>().First(predicate);
    }

    public static Match FirstOrDefault(this MatchCollection source)
    {
        return (source == null || source.Count == 0) ? null : source[0];
    }

    public static Match FirstOrDefault<T>(this MatchCollection source, Func<Match, bool> predicate)
    {
        return source.Cast<Match>().FirstOrDefault(predicate);
    }

    public static Match Last<T>(this MatchCollection source)
    {
        return (source == null || source.Count == 0) ? null : source[0];
    }

    public static Match Last(this MatchCollection source, Func<Match, bool> predicate)
    {
        return source.Cast<Match>().Last(predicate);
    }

    public static Match LastOrDefault(this MatchCollection source)
    {
        return (source == null || source.Count == 0) ? null : source[source.Count - 1];
    }

    public static Match LastOrDefault<T>(this MatchCollection source, Func<Match, bool> predicate)
    {
        return source.Cast<Match>().LastOrDefault(predicate);
    }

    public static IOrderedEnumerable<Match> OrderBy<Match, TKey>(this MatchCollection source, Func<Match, TKey> keySelector)
    {
        return source.Cast<Match>().OrderBy(keySelector);
    }

    public static IOrderedEnumerable<Match> OrderBy<Match, TKey>(this MatchCollection source, Func<Match, TKey> keySelector, IComparer<TKey> comparer)
    {
        return source.Cast<Match>().OrderBy(keySelector, comparer);
    }

    public static IOrderedEnumerable<Match> OrderByDescending<Match, TKey>(this MatchCollection source, Func<Match, TKey> keySelector)
    {
        return source.Cast<Match>().OrderByDescending(keySelector);
    }

    public static IOrderedEnumerable<Match> OrderByDescending<Match, TKey>(this MatchCollection source, Func<Match, TKey> keySelector, IComparer<TKey> comparer)
    {
        return source.Cast<Match>().OrderByDescending(keySelector, comparer);
    }

    public static IEnumerable<Match> Reverse(this MatchCollection source)
    {
        return source.Cast<Match>().Reverse();
    }

    public static IEnumerable<TResult> Select<TResult>(this MatchCollection source, Func<Match, TResult> selector)
    {
        return source.Cast<Match>().Select(selector);
    }

    public static IEnumerable<TResult> Select<TResult>(this MatchCollection source, Func<Match, int, TResult> selector)
    {
        return source.Cast<Match>().Select(selector);
    }

    public static IEnumerable<Match> Skip(this MatchCollection source, int count)
    {
        return source.Cast<Match>().Skip(count);
    }

    public static IEnumerable<Match> Take(this MatchCollection source, int count)
    {
        return source.Cast<Match>().Take(count);
    }

    public static Dictionary<TKey, Match> ToDictionary<Match, TKey>(this MatchCollection source, Func<Match, TKey> keySelector)
    {
        return source.Cast<Match>().ToDictionary(keySelector);
    }

    public static Dictionary<TKey, Match> ToDictionary<Match, TKey>(this MatchCollection source, Func<Match, TKey> keySelector, IEqualityComparer<TKey> comparer)
    {
        return source.Cast<Match>().ToDictionary(keySelector, comparer);
    }

    public static Dictionary<TKey, TElement> ToDictionary<Match, TKey, TElement>(this MatchCollection source, Func<Match, TKey> keySelector, Func<Match, TElement> elementSelector)
    {
        return source.Cast<Match>().ToDictionary(keySelector, elementSelector);
    }

    public static Dictionary<TKey, TElement> ToDictionary<Match, TKey, TElement>(this MatchCollection source, Func<Match, TKey> keySelector, Func<Match, TElement> elementSelector, IEqualityComparer<TKey> comparer)
    {
        return source.Cast<Match>().ToDictionary(keySelector, elementSelector, comparer);
    }

    public static List<Match> ToList<T>(this MatchCollection source)
    {
        return source.Cast<Match>().ToList();
    }

    public static IEnumerable<Match> Where<T>(this MatchCollection source, Func<Match, bool> predicate)
    {
        return source.Cast<Match>().Where(predicate);
    }
}

The MemoryCache class is another fundamentally useful .NET class that has a bit of a clumsy API, which can be remedied by providing facades to the clunkier methods. Very often one merely wants to set a cache duration when setting an object, and get an object of a specified type safely.

using System;
using System.Runtime.Caching;

public static partial class MemoryCacheExtensions
{
    public static void Set(this MemoryCache cache, string key, object value, long durationMilliseconds)
    {
        if (cache == null || key == null) throw new ArgumentNullException();
        else if (durationMilliseconds <= 0) return;
        else if (value == null)
            try { cache.Remove(key); } catch {}

        DateTimeOffset expiration = DateTime.Now.AddMilliseconds(durationMilliseconds);
        cache.Set(key, value, expiration);
    }

    public static T Get<T>(this MemoryCache cache, string key, T defaultValue = default(T))
    {
        object value = cache.Get(key);

        if (value == null || !(value is T))
            return defaultValue;
        else
            return (T)value;
    }
}

The common thread in these examples is that even in the .NET FCL (and CoreFX for that matter), API design is not always optimal. A primary use case for extension methods is where a developer desires to add useful functionality to an API, but without the ability to control the API itself, and this applies to .NET fundamentals as easily as anything else. When one is adding those methods to a core class, it may make sense to make the extension methods themselves as visible as the core classes so extended–and here the efficiency/usability gains of broadening visibility can be tainting in a sense, as above where the MatchCollection extensions are made global by virtue of the fact they may be returned from the result of another global extension method on the String class.

This may not be everyone’s cup of tea, and in fact I don’t tend to do this for seldom-used, specialty classes ever. The String class is obviously a different case from even MatchCollection and the like. And whenever creating extension methods, but increasing with their visibility, one should strongly consider placing them in partial, wisely named classes to avoid naming collisions in the future.

An Aspect-Oriented Programming (AOP) Approach to Logging

New: Dynamically evaluate C# expressions and execute C# scripts with a single statement, from anywhere in a .NET application. Click here for more info.

Logging is a topic near and dear to my heart, having in an earlier version of .NET created a logging package tuned for high performance and used many others since. Today, with multiple popular offerings available to the .NET developer with different strengths and weaknesses (NLog, Log4Net, Serilog et al.) it’s not unusual to see adapters in local codebases to allow configuration and use of different packages as desired. This is actually a practice I recommend, to decouple local APIs from the implementation of a solution to a common and cross-cutting concern.

This naturally leads to thoughts of simplifying access in one’s API to the logging code. Aspect-oriented logging has in the past included attribute-based approaches, such as in PostSharp. But what if one hasn’t adopted such a library, or would like to log statements from code inside existing methods?

Suppose that one has logging classes presumably configured using some IoC implementation, and wants to decorate an API with logging functionality without undue clutter. One can use C# extension methods and weak references together with a marker interface to achieve the desired effect. Here are the steps:

1. Create an interface with which to decorate classes that will generate log information. (In the linked code sample, see the ILogSource interface.)

2. Add extensions to the log-source interface to support logging messages and/or events, corresponding with the desired use of the logging API, and to get and set a logger using a weak reference. (In the linked code sample, see the ILogSourceExtensions static class, stored with ILogSource in ILogSource.cs).

3. Decorate any desired class with logging functionality by implementing the marker interface, and configuring it with a logger as desired, then calling its logging methods within its other code. (See the code sample for more.)

This approach still allows an adapter to a target logging API to be used, and run-time configuration of the implementation as desired. It merely provides syntactic sugar to avoid littering your API with logging substructure in base classes and the like, by reducing the necessary plumbing to a single interface marked on the logging client class. The overhead of looking up the weak-referenced logger turns out to be minimal, at several nanoseconds per call. I’m still thinking through how best to wire this together with injection; constructor injection seems to obviously be out of the question.

Extension methods + weak references = extension pseudo-properties in C#

New: Dynamically evaluate C# expressions and execute C# scripts with a single statement, from anywhere in a .NET application. Click here for more info.

When the below was first written, extension properties were just wishful thinking. However, check out the upcoming “Extension Everything” features slated for C# 8. Unfortunately, additional state is apparently not yet to be supported directly, but at least the property syntax will be cleaner; state can be dummied up as necessary using the below approach.

Note: A full reference implementation including extension methods for both setting/getting extra item data, as well as caching, is available at the SharpByte project. See ObjectExtensions.cs.

Extension methods can be helpful for adding functionality onto existing classes, especially where one doesn’t have the ability to control a class definition and thus can’t add the methods directly. Adding extension properties to C# could be just as useful in some programming scenarios, but so far isn’t slated for definite release. Yet when working with third-party code such as the Sitecore API, it can be especially useful to add on both post-hoc functionality and state. And while extension methods can’t precisely duplicate the syntax of properties in C#, they can come close through the use of getter/setter methods as in Java, if some facility is used to store data on the object.

The System.Runtime.CompilerServices.ConditionalWeakTable class is ideal for such use, as a collection specifically made to contain weak references, i.e. to allow any referred-to object to be garbage collected (releasing the weak reference as well) if all strong references have been removed. What this means on a practical basis is that one can provide ancillary state for an object by using such a weak-reference collection in a static, and ideally thread-safe, way. It’s exactly what’s needed to dummy up extension properties in C#, while we wait for the real deal from Microsoft.

Here’s a basic example:

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

public static class ExtendedDataExtensions
{
    ///<summary>Stores extended data for objects</summary>
    private static ConditionalWeakTable<object, object> extendedData = new ConditionalWeakTable<object, object>();

    /// <summary>
    /// Creates a collection of extended pseudo-property values
    /// </summary>
    /// <param name="o">The object to receive the tacked-on data values</param>
    /// <returns>A new dictionary</returns>
    internal static IDictionary<string, object> CreateObjectExtendedDataCache(object o)
    {
        return new Dictionary<string, object>();
    }

    /// <summary>
    /// Sets an extended pseudo-property value on this object
    /// </summary>
    /// <param name="o">this object</param>
    /// <param name="name">The pseudo-property name</param>
    /// <param name="value">The value to set (if null, any value for the name will be removed)</param>
    public static void SetExtendedDataValue(this object o, string name, object value)
    {
        if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Invalid name");
        name = name.Trim();

        // Gets the key-value collection serving as extended "properties" for this object
        IDictionary<string, object> values = (IDictionary<string, object>)extendedData.GetValue(o, CreateObjectExtendedDataCache);

        if (value != null)
            values[name] = value;
        else
            values.Remove(name);
    }

    /// <summary>
    /// Gets a pseudo-property value stored for this object
    /// </summary>
    /// <typeparam name="T">The type to return</typeparam>
    /// <param name="o">this object</param>
    /// <param name="name">The pseudo-property name</param>
    /// <returns>A value of the indicated type, or the type default if not found or of a different type</returns>
    public static T GetExtendedDataValue<T>(this object o, string name)
    {
        if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Invalid name");
        name = name.Trim();

        IDictionary<string, object> values = (IDictionary<string, object>)extendedData.GetValue(o, CreateObjectExtendedDataCache);
        object value = null;
        if (values.TryGetValue(name, out value)) 
        {
            if (value is T)
                return (T)value;
            else
                return default(T); // or throw an exception, as desired
        }
        else
            return default(T);
    }

    /// <summary>
    /// Gets a pseudo-property value stored for this object
    /// </summary>
    /// <param name="o">this object</param>
    /// <param name="name">The pseudo-property name</param>
    /// <returns>A value if found for the specified name, otherwise null</returns>
    public static object GetExtendedDataValue(this object o, string name)
    {
        if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Invalid name");
        name = name.Trim();

        IDictionary<string, object> values = (IDictionary<string, object>)extendedData.GetValue(o, CreateObjectExtendedDataCache);
        object value = null;
        if (values.TryGetValue(name, out value))
            return value;
        else
            return null;
    }
}

A brief example of calling the methods:

Item item = Sitecore.Context.Item;
item.SetExtendedDataValue("Tweet Count", 300);
// ...
int tweetCount = item.GetExtendedDataValue<int>("Tweet Count");

… after which one’s thoughts naturally turn to wrapping things up a bit more nicely, seasoning to taste for such issues as null and range checking. An inane example, for want of a better one:

public static class ItemExtensions
{
    public static int GetTweetCount(this Item item)
    {
        return item.GetExtendedDataValue<int>("Tweet Count");
    }

    public static void SetTweetCount(this Item item, int tweetCount)
    {
        item.SetExtendedDataValue("Tweet Count", tweetCount);
    }
}

And, of course, if it’s desired to make the pseudo-properties thread-safe, merely replace the dictionary storage with ConcurrentDictionary, with nearly identical performance.