A great thing about .NET Expression Trees is you can compile them at runtime, and they’ll execute as fast as any .NET code.  However, while building and compiling a tree is pretty quick, it’s best if you only need to do it once.

The way you’d usually do that is cache the compiled delegate somewhere.  If you just want to create it and use it repeatedly in the same code block, just hold the delegate in a local variable:

void Main()
{
    var dump = MakeDumpDelegate<DateTime>();

    for ( var yearOffset = 0; yearOffset < 5; ++ yearOffset )
    {
        Console.WriteLine( string.Join( " | ", dump( DateTime.Now.AddYears( yearOffset ) ) ) );
    }
}

Func<TModel, object[]> MakeDumpDelegate<TModel>()
{
    var modelParam = Expression.Parameter( typeof( TModel ), "model" );
    var properties = typeof( TModel ).GetProperties( BindingFlags.Public | BindingFlags.Instance ).OrderBy( p => p.Name );

    var lambda = Expression.Lambda<Func<TModel, object[]>>(
        Expression.NewArrayInit(
            typeof( object ),
            from p in properties
            select Expression.Convert( Expression.MakeMemberAccess( modelParam, p ), typeof( object ) ) ),
        modelParam );

    return lambda.Compile();
}

Here MakeDumpDelegate creates a delegate that takes an object of type TModel, and returns an object array of its alphabetically sorted property values.  In the Main method we’re creating a delegate based on the DateTime type, running it 5 times and spitting out the values.

What if there are a bunch of classes we want to run delegates for?  We could move the code out of Main and call it wherever we need it:

void Main()
{
    var dates = Enumerable.Range( 0, 5 ).Select( yo => DateTime.Now.AddYears( yo ) );

    foreach ( var d in DumpProperties( dates ) )
    {
        Console.WriteLine( d );
    }
}

IEnumerable<string> DumpProperties<TModel>( IEnumerable<TModel> models )
{
    var dump = MakeDumpDelegate<TModel>();

    return from m in models select string.Join( " | ", dump( m ) );
}

This works great, and we can call DumpProperties with any collection we like.  The problem is, we’re building and compiling the expression tree every time we use it.  This is pretty inefficient, so let’s add a cache of delegates for each type.

But wait…  Let’s say we want to hit these things from multiple threads.  We’re probably going to need a static Dictionary<Type, delegate> to hold onto them, and we’ll need to provide some locking to stop the threads messing us up.  This is too complicated to be good.

Instead, we’ll use a generic class and let .NET help us out.  When you declare a generic class, each specialization of that class gets its own copy of its static members:

class MyClass<T>
{
    public static T MyStaticValue { get; set; }
}

So if you access MyClass<int>.MyStaticValue or MyClass<double>.MyStaticValue, they’re obviously different instances (one is int and the other double).  We can use this to hold onto our delegate:

void Main()
{
    var dates = Enumerable.Range( 0, 5 ).Select( yo => DateTime.Now.AddYears( yo ) );

    foreach ( var d in DumpProperties( dates ) )
    {
        Console.WriteLine( d );
    }
}

IEnumerable<string> DumpProperties<TModel>( IEnumerable<TModel> models )
{
    var dump = DumpDelegate<TModel>.Dump;

    return from m in models select string.Join( " | ", dump( m ) );
}

class DumpDelegate<TModel>
{
    public static Func<TModel, object[]> Dump { get; private set; }

    static DumpDelegate()
    {
        var modelParam = Expression.Parameter( typeof( TModel ), "model" );
        var properties = typeof( TModel ).GetProperties( BindingFlags.Public | BindingFlags.Instance ).OrderBy( p => p.Name );
    
        var lambda = Expression.Lambda<Func<TModel, object[]>>(
            Expression.NewArrayInit(
                typeof( object ),
                from p in properties
                select Expression.Convert( Expression.MakeMemberAccess( modelParam, p ), typeof( object ) ) ),
            modelParam );

        Dump = lambda.Compile();
    }
}

What’s great about this is .NET guarantees the static constructor will only be called once, and in a completely thread-safe manner.  Since DumpDelegate is a generic class based on TModel, each specialization will only be initialized once – and only on first use.  Our threading headache has just disappeared, and we’re building and compiling the tree just once for each model type Smile

kick it on DotNetKicks.com

Live in Minnesota?  http://tccc12.eventbrite.com Smile

On the second Thursday of the month at 5pm, the Rochester, MN .NET User Group meets at Mann Hall.  You’re very welcome to join us if you’re in the area.

We often have someone interesting presenting something exciting, but occasionally that doesn’t work out and I’ll present something instead Winking smile  This is where the LOLCode Parser was born…

First you should try it out here.  It’ll ask you to write some LOLCode and optionally give it some inputs to pass in.  Let’s start with “Hai World”…

HAI
CAN HAS STDIO?
VISIBLE "HAI WORLD!" N " I SLEEPIN"
KTHXBYE

Paste that and click the “PLZ RUN THE CODE 4 ME” button.  This demonstrates the VISIBLE statement and the N concatenation operator.

Let’s step it up a bit and add some conditions (to see this work its magic, you’ll need an input value in the second textbox):

HAI
CAN HAS STDIO?
I HAS A VAR
VISIBLE "GIMMEH INPUTZ!..."
GIMMEH VAR
VISIBLE "U SEZ " N VAR
IZ VAR BIGR THAN 10?
    YARLY
        BTW this is true
        VISIBLE VAR N " IZ BIG NUMBER!"
    NOWAI
        BTW this is false
        VISIBLE VAR N " IZ LITTLE NUMBER!"
KTHX
VISIBLE "I IZ DONE"
KTHXBYE

Here we’ve added some user input (GIMMEH VAR will read a line from the input source to the VAR variable). The IZ..YARLY..NOWAI..KTHX construct lets us specify a condition based on its value. The BTW statement begins a comment.

Cats won’t usually chase their tails like dogs will, but they use loops to remind their owners it’s feeding time. This one just wants to count to 10 between meows:

HAI
CAN HAS STDIO?
VISIBLE "HAI WORLD!"
I HAS A VAR
IM IN YR KITCHN
    UPZ VAR!!1
    VISIBLE VAR
    IZ VAR BIGR THAN 9? GTFO. KTHX
KTHX
VISIBLE "FEED MEOW!"
KTHXBYE

If you’re thinking this isn’t very impressive, you’re right.  Still, it does have some cool points:

  • It’s using a parser generated by TinyPG (awesome tool on CodeProject by Herre Kuijpers).
  • The LOLCode is being parsed into a LINQ expression tree (similar to this old post, but no DLR and much simpler).
  • Because it’s an expression tree, it can be compiled and cached on the server.  This should run as fast as C#, so your cat will be happy.  For this demo, if you don’t change the code between requests it’ll just run the cached, pre-compiled code.  Anything in the Inputs box is passed as a parameter.
  • This isn’t just an expression returning a value; it’s building a full LOLCode program (with conditions, loops etc).
  • It allows your program to run for up to two seconds; if it overstays its welcome, it will be brutally terminated (putting your cat in an infinite loop is animal cruelty).

You’re unlikely to want LOLCode in your own apps, but some of the ideas could be useful.  For example, you could use it to provide a custom scripting language for clients to automate aspects of your apps.

You can find the source code here.  It’s pretty easy to use TinyPG to define your own parser (see the Cjc.LOLCode.tpg file for sample syntax), then extend the ParseTreeVisitor / Visitor classes to build an expression tree.

Finally, here’s some bonus LOLCode:

HAI
CAN HAS STDIO?
VISIBLE "HAI WORLD!"
I HAS A VAR
I HAS A INPUTZ
IM IN YR KITCHN
    UPZ VAR!!1
    GIMMEH INPUTZ
    VISIBLE VAR N ", " N INPUTZ
    IZ VAR BIGR THAN 9? GTFO. KTHX
KTHX
VISIBLE "FEED MEOW!"
KTHXBYE

And some inputs to go with it:

10
9
8
7
6
5
4
3
2
1

You might also want to take a look at a LOLQL parser (source here); it allows your cat to query a database through Entity Framework!

DotNetKicks Image

UPDATE: There are other petitions covering similar topics, with many more votes so far.  I’ve added them to the end of this post…

If you live in the US, please take a look at this petition to allow H4 visa holders (spouses etc who are wholly dependent on other visa holders, like H1’s – which companies like Microsoft benefit from) to seek employment:

http://wh.gov/gDr

It’s on the new “We the People” page on the White House site…  Pretty cool, although interesting to see legalizing marijuana and acknowledging an “extra terrestrial presence engaging the human race” are considered such major priorities Winking smile

Thanks!

Other similar petitions:

DotNetKicks Image

Awesomium v1.6 is finally out, with a very awesome free license for indie developers.  It includes AwesomiumSharp, which means you cam do all kinds of cool and crazy .NET stuff with it Smile

Go get it here! (or at http://awesomium.com).

DotNetKicks Image

UPDATE – Beefed up the regular expression for better handling of nested parentheses.

LINQ To SQL doesn’t provide a way to include Xquery expressions in queries.  The simplest solution is to create SQL user-defined functions that perform the Xquery for you and return scalar results.

This works pretty well for small databases, but you lose the benefit of SQL Server’s XML indexes.  To get around that, we can modify the SQL command text to expand the function calls into raw Xquery expressions.

There are a couple of ways to do this, depending on the complexity / flexibility required for your query.  For simple queries you can use the DataContext.GetCommand method, modify the command, and get the results through DataContext.Translate or DataContext.ExecuteQuery.  For complex queries (particularly ones that need to shape the results) you’ll need to jump through a couple of Reflection hoops.

Since we don’t actually need to call the SQL user-defined functions, we can just create empty placeholders.  Here’s a sample table and functions:

-- =============================================
-- Author:      Chris Cavanagh
-- Create date: 3/15/2011
-- Description: Demo table
-- =============================================
CREATE TABLE [dbo].[MyXmlFieldTable](
    [UID] [uniqueidentifier] NOT NULL,
    [TimeCreated] [datetime] NOT NULL,
    [XmlValues] [xml] NULL,
 CONSTRAINT [PK_MyXmlFieldTable] PRIMARY KEY
(
    [UID] ASC
) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[MyXmlFieldTable] ADD  CONSTRAINT [DF_MyXmlFieldTable_TimeCreated]  DEFAULT (getdate()) FOR [TimeCreated]
GO

-- =============================================
-- Author:      Chris Cavanagh
-- Create date: 3/15/2011
-- Description: Get XQuery value (string)
-- =============================================
CREATE FUNCTION XQueryString
(
    @xml xml,
    @xpath varchar(200)
)
RETURNS nvarchar(4000)
AS
BEGIN
    DECLARE @Result nvarchar(4000)
    RETURN @Result
END
GO

-- =============================================
-- Author:      Chris Cavanagh
-- Create date: 3/15/2011
-- Description: Get XQuery value (datetime)
-- =============================================
CREATE FUNCTION XQueryDateTime
(
    @xml xml,
    @xpath varchar(200)
)
RETURNS datetime
AS
BEGIN
    DECLARE @Result datetime
    RETURN @Result
END
GO

-- =============================================
-- Author:      Chris Cavanagh
-- Create date: 3/15/2011
-- Description: Get XQuery value (float)
-- =============================================
CREATE FUNCTION XQueryFloat
(
    @xml xml,
    @xpath varchar(200)
)
RETURNS float
AS
BEGIN
    DECLARE @Result float
    RETURN @Result
END
GO

-- =============================================
-- Author:      Chris Cavanagh
-- Create date: 3/15/2011
-- Description: Get XQuery value (bit)
-- =============================================
CREATE FUNCTION XQueryBit
(
    @xml xml,
    @xpath varchar(200)
)
RETURNS bit
AS
BEGIN
    DECLARE @Result bit
    RETURN @Result
END
GO

-- =============================================
-- Author:      Chris Cavanagh
-- Create date: 3/15/2011
-- Description: Get XQuery value (compare)
-- =============================================
CREATE FUNCTION XQueryCompare
(
    @xml xml,
    @xpath varchar(200),
    @oper varchar(10),
    @value nvarchar(4000)
)
RETURNS bit
AS
BEGIN
    DECLARE @Result bit
    RETURN @Result
END
GO

Once you add these functions to your DBML file (through the designer, or manually if you prefer) you’ll be able to write LINQ queries that call them.  Here’s a simple example:

var results = from r in MyXmlFieldTable
    let date = context.XQueryDateTime( r.XmlValues, "MyContainer/MyDateTime" )
    where date < DateTime.Now.AddDays( -5 )
    select new
    {
        Date = date,
        FirstName = context.XQueryString( r.XmlValues, "MyContainer/FirstName" ),
        LastName = context.XQueryString( r.XmlValues, "MyContainer/LastName" )
    };

With this, we can use some Regex magic to expand the function names into XQuery expressions:

public class XQueryHelper
{
    private static Regex regex = new Regex( @"\[dbo\]\.\[XQuery(?<type>.*?)\]\(\s?(?<column>\([^\(\)]*(((?'Open'\()[^\(\)]*)+((?'Close-Open'\))[^\(\)]*)+)*(?(Open)(?!))\)|([\s\S]*?)),\s?(?<xpath>.*?)(,\s?(?<oper>.*?),\s?(?<value>.*?))?\s?\)", RegexOptions.Compiled );

    public static string OptimizeSql( string commandText, IDictionary<string, object> parameters )
    {
        return regex.Replace(
            commandText,
            delegate( Match m )
            {
                var column = m.Groups[ "column" ].Value;
                var xpath = parameters[ m.Groups[ "xpath" ].Value ];

                var sqlType = "nvarchar( 4000 )";
                var compare = "";
                var type = m.Groups[ "type" ].Value;

                switch ( type )
                {
                    case "Float": sqlType = "float"; break;
                    case "DateTime": sqlType = "datetime"; break;
                    case "Bit": sqlType = "int"; compare = " = 1"; break;
                    case "Compare":
                    {
                        var oper = parameters[ m.Groups[ "oper" ].Value ];
                        var valueParam = m.Groups[ "value" ].Value;

                        var value = valueParam.StartsWith( "@" )
                            ? string.Format( "sql:variable(\"{0}\")", valueParam )
                            : string.Format( "\"{0}\"", valueParam );

                        return string.Format( "{0}.exist('{1}[.{2}{3}]')", column, xpath, oper, value );
                    }
                }

                return string.Format( "{0}.value('({1})[1]', '{2}'){3}", column, xpath, sqlType, compare );
            } );
    }
}

Here’s where you need to decide between the “safe” and risky ways to manipulate the command text.  Here’s the safe way:

    var command = context.GetCommand( results );
    var parameters = command.Parameters.Cast<DbParameter>().ToDictionary( p => p.ParameterName, p => p.Value );

    command.CommandText = XQueryHelper.OptimizeSql( command.CommandText, parameters );

    var newResults = context.ExecuteQuery( command.CommandText, parameters.Values );

The riskier (but more flexible and robust) way is discussed here.  Using this, all you need to do is modify your DataContext before executing the query.

    context = DataContextInterceptor.Intercept( context, XQueryHelper.OptimizeSql );

Hope you find this useful! Smile

DotNetKicks Image

UPDATE 2 – Improved version that correctly handles sub-queries can be found here.

UPDATE – To see an example use for this code, see this post where I discuss supporting native XQuery using LINQ to SQL.

HACK WARNING – This example calls private framework methods through Reflection.  It’s bad practice in almost every way.  Also, it’s unlikely to work in a partial trust environment.  Use at your own risk Smile

Here’s a bit of code that’ll let you modify any command text LINQ To SQL generates before it hits the database.  It’s always been possible to call DataContext.GetCommand and use modified SQL in a call to DataContext.Translate or DataContext.ExecuteQuery, but that’s pretty restrictive in the complexity of query you can use.  Also, if LINQ To SQL decides it needs to batch multiple SELECT statements for the desired results, GetCommand can only give you the first one.

The first thing to do is replace the IProvider implementation used by your DataContext.  Unfortunately, DataContext’s Provider property is both private and read-only.  Also, the IProvider interface itself is private.  This is bad in every way, and we absolutely shouldn’t try to hack our way through that… but we will.

Inspired by a 2008 post by Matt Warren, I made the following DataContextInterceptor helper.  It intercepts calls to the IProvider’s Compile and Execute methods.  Rather than rewrite most of the SqlProvider code, it calls the same private methods it normally would, albeit through reflection.  The only other thing it does is call the ModifyCommandDelegate delegate (assigned by your code) with the command text and parameters.

Although it’s not the cleanest solution, it’s pretty much transparent to LINQ To SQL.  You can use complex queries (even compiled ones via CompiledQuery.Compile) and they work just fine:

    public class DataContextInterceptor
    {
        public delegate string ModifyCommandDelegate( string commandText, IDictionary<string, object> parameters );

        private DataContext dc;
        private object oldProvider;
        private Type providerType;
        private ModifyCommandDelegate modifyCommand;

        public static TDataContext Intercept<TDataContext>( TDataContext dc, ModifyCommandDelegate modifyCommand )
            where TDataContext : DataContext
        {
            new DataContextInterceptor( dc, modifyCommand );

            return dc;
        }

        public DataContextInterceptor( DataContext dc, ModifyCommandDelegate modifyCommand )
        {
            this.dc = dc;
            this.modifyCommand = modifyCommand;

            FieldInfo providerField = typeof( DataContext ).GetField( "provider", BindingFlags.Instance | BindingFlags.NonPublic );
            var existingProvider = providerField.GetValue( dc );

            if ( existingProvider is SqlProvider )
            {
                oldProvider = existingProvider;

                var proxy = new ProviderProxy( this, oldProvider ).GetTransparentProxy();

                providerField.SetValue( dc, proxy );
            }
        }

        public static MethodInfo GetMethod( Type type, string methodName, params object[] args )
        {
            var hasNullArgs = args.Any( a => a == null );

            var method = hasNullArgs
                ? type.GetMethods( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic )
                    .FirstOrDefault( m => m.Name == methodName )
                : null;

            if ( method == null && !hasNullArgs )
            {
                method = type.GetMethod(
                    methodName,
                    BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
                    null,
                    args.Select( a => a.GetType() ).ToArray(),
                    null );
            }

            return method;
        }

        private object Invoke( object instance, string methodName, params object[] args )
        {
            var type = instance.GetType();
            var method = GetMethod( type, methodName, args );

            return ( method != null )
                ? method.Invoke( instance, args )
                : null;
        }

        private object Invoke( Type type, string methodName, params object[] args )
        {
            var method = type.GetMethod( methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic );

            return method.Invoke( null, args );
        }

        protected object CompileImpl( Expression query )
        {
            var assembly = typeof( SqlProvider ).Assembly;

            /*
            this.CheckDispose();
            this.CheckInitialized();
            if ( query == null )
            {
                throw Error.ArgumentNull( "query" );
            }
            */

            // this.InitializeProviderMode();
            Invoke( oldProvider, "InitializeProviderMode" );

            // SqlNodeAnnotations annotations = new SqlNodeAnnotations();
            var annotations = Activator.CreateInstance( assembly.GetType( "System.Data.Linq.SqlClient.SqlNodeAnnotations" ) );

            // QueryInfo[] queries = this.BuildQuery( query, annotations );
            var queries = Invoke( oldProvider, "BuildQuery", query, annotations );

            var info = ModifyQueries( (IEnumerable)queries );

            // this.CheckSqlCompatibility( queries, annotations );
            Invoke( oldProvider, "CheckSqlCompatibility", queries, annotations );

            LambdaExpression expression = query as LambdaExpression;

            if ( expression != null )
            {
                query = expression.Body;
            }

            // IObjectReaderFactory readerFactory = null;
            object readerFactory = null;

            // ICompiledSubQuery[] subQueries = null;
            object subQueries = null;

            // QueryInfo info = queries[ queries.Length - 1 ];
            // info defined above

            var resultShape = (int)Invoke( info, "get_ResultShape" );

            // if ( info.ResultShape == ResultShape.Singleton )
            if ( resultShape == 1 /* Singleton */ )
            {
                // subQueries = this.CompileSubQueries( info.Query );
                subQueries = Invoke( oldProvider, "CompileSubQueries", Invoke( info, "get_Query" ) );

                // readerFactory = this.GetReaderFactory( info.Query, info.ResultType );
                readerFactory = Invoke( oldProvider, "GetReaderFactory", Invoke( info, "get_Query" ), Invoke( info, "get_ResultType" ) );
            }
            // else if ( info.ResultShape == ResultShape.Sequence )
            else if ( resultShape == 2 /* Sequence */ )
            {
                // subQueries = this.CompileSubQueries( info.Query );
                subQueries = Invoke( oldProvider, "CompileSubQueries", Invoke( info, "get_Query" ) );

                // readerFactory = this.GetReaderFactory( info.Query, TypeSystem.GetElementType( info.ResultType ) );
                var resultType = Invoke( info, "get_ResultType" );
                var typeSystemType = assembly.GetType( "System.Data.Linq.SqlClient.TypeSystem" );
                var elementType = Invoke( typeSystemType, "GetElementType", resultType );

                readerFactory = Invoke( oldProvider, "GetReaderFactory", Invoke( info, "get_Query" ), elementType );
            }

            FieldInfo providerField = typeof( DataContext ).GetField( "provider", BindingFlags.Instance | BindingFlags.NonPublic );
            providerField.SetValue( dc, oldProvider );

            // return new CompiledQuery( this, query, queries, readerFactory, subQueries );
            var compiledQueryType = assembly.GetType( "System.Data.Linq.SqlClient.SqlProvider+CompiledQuery" );

            return Activator.CreateInstance(
                compiledQueryType,
                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
                null,
                new object[] { oldProvider, query, queries, readerFactory, subQueries },
                null );
        }

        protected internal virtual IExecuteResult ExecuteImpl( Expression query )
        {
            var assembly = typeof( SqlProvider ).Assembly;

            /*
            this.CheckDispose();
            this.CheckInitialized();
            this.CheckNotDeleted();
            if (query == null)
            {
                throw Error.ArgumentNull("query");
            }
            */

            // this.InitializeProviderMode();
            Invoke( oldProvider, "InitializeProviderMode" );

            // query = Funcletizer.Funcletize(query);
            var funcletizerType = assembly.GetType( "System.Data.Linq.SqlClient.Funcletizer" );
            query = (Expression)Invoke( funcletizerType, "Funcletize", query );

            // if ( this.EnableCacheLookup )
            if ( (bool)Invoke( oldProvider, "get_EnableCacheLookup" ) )
            {
                // IExecuteResult cachedResult = this.GetCachedResult(query);
                object cachedResult = Invoke( oldProvider, "GetCachedResult", query );

                if ( cachedResult != null )
                {
                    // return cachedResult;
                    return (IExecuteResult)cachedResult;
                }
            }

            // SqlNodeAnnotations annotations = new SqlNodeAnnotations();
            var annotations = Activator.CreateInstance( assembly.GetType( "System.Data.Linq.SqlClient.SqlNodeAnnotations" ) );

            // QueryInfo[] queries = this.BuildQuery(query, annotations);
            var queries = Invoke( oldProvider, "BuildQuery", query, annotations );

            var info = ModifyQueries( (IEnumerable)queries );

            // this.CheckSqlCompatibility(queries, annotations);
            Invoke( oldProvider, "CheckSqlCompatibility", queries, annotations );

            LambdaExpression expression = query as LambdaExpression;

            if ( expression != null )
            {
                query = expression.Body;
            }

            // IObjectReaderFactory readerFactory = null;
            object readerFactory = null;

            // ICompiledSubQuery[] subQueries = null;
            object subQueries = null;

            // QueryInfo info = queries[queries.Length - 1];
            // info defined above

            var resultShape = (int)Invoke( info, "get_ResultShape" );

            // if (info.ResultShape == ResultShape.Singleton)
            if ( resultShape == 1 /* Singleton */ )
            {
                // subQueries = this.CompileSubQueries(info.Query);
                subQueries = Invoke( oldProvider, "CompileSubQueries", Invoke( info, "get_Query" ) );

                // readerFactory = this.GetReaderFactory(info.Query, info.ResultType);
                readerFactory = Invoke( oldProvider, "GetReaderFactory", Invoke( info, "get_Query" ), Invoke( info, "get_ResultType" ) );
            }
            // else if (info.ResultShape == ResultShape.Sequence)
            else if ( resultShape == 2 /* Sequence */ )
            {
                // subQueries = this.CompileSubQueries(info.Query);
                subQueries = Invoke( oldProvider, "CompileSubQueries", Invoke( info, "get_Query" ) );

                // readerFactory = this.GetReaderFactory(info.Query, TypeSystem.GetElementType(info.ResultType));
                var resultType = Invoke( info, "get_ResultType" );
                var typeSystemType = assembly.GetType( "System.Data.Linq.SqlClient.TypeSystem" );
                var elementType = Invoke( typeSystemType, "GetElementType", resultType );

                readerFactory = Invoke( oldProvider, "GetReaderFactory", Invoke( info, "get_Query" ), elementType );
            }

            // return this.ExecuteAll(query, queries, readerFactory, null, subQueries);
            return (IExecuteResult)Invoke( oldProvider, "ExecuteAll", query, queries, readerFactory, null, subQueries );
        }

        private object ModifyQueries( IEnumerable queries )
        {
            object lastQuery = null;

            foreach ( var q in queries )
            {
                lastQuery = q;

                var commandTextField = q.GetType().GetField( "commandText", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic );
                var parametersField = q.GetType().GetField( "parameters", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic );

                var commandText = (string)commandTextField.GetValue( q );
                var parameters = new Dictionary<string, object>();

                foreach ( var p in (IEnumerable)parametersField.GetValue( q ) )
                {
                    var name = (string)Invoke( Invoke( p, "get_Parameter" ), "get_Name" );
                    parameters[ name ] = Invoke( p, "get_Value" );
                }

                var modifiedCommandText = modifyCommand( commandText, parameters );

                commandTextField.SetValue( q, modifiedCommandText );
            }

            return lastQuery;
        }

        public class ProviderProxy : RealProxy, IRemotingTypeInfo
        {
            DataContextInterceptor extender;
            object oldProvider;

            internal ProviderProxy( DataContextInterceptor extender, object oldProvider )
                : base( typeof( ContextBoundObject ) )
            {
                this.extender = extender;
                this.oldProvider = oldProvider;
            }

            public override IMessage Invoke( IMessage msg )
            {
                if ( msg is IMethodCallMessage )
                {
                    IMethodCallMessage call = (IMethodCallMessage)msg;
                    MethodInfo mi = null;

                    if ( call.MethodBase.DeclaringType.Name == "IProvider" && call.MethodBase.DeclaringType.IsInterface )
                    {
                        extender.providerType = call.MethodBase.DeclaringType;

                        mi = DataContextInterceptor.GetMethod( typeof( DataContextInterceptor ), call.MethodBase.Name + "Impl", call.Args );

                        if ( mi == null && oldProvider != null )
                        {
                            mi = DataContextInterceptor.GetMethod( call.MethodBase.DeclaringType, call.MethodBase.Name, call.Args );

                            return new ReturnMessage( mi.Invoke( oldProvider, call.Args ), null, 0, null, call );
                        }

                        if ( mi != null )
                        {
                            try
                            {
                                return new ReturnMessage( mi.Invoke( this.extender, call.Args ), null, 0, null, call );
                            }
                            catch ( TargetInvocationException e )
                            {
                                return new ReturnMessage( e.InnerException, call );
                            }
                        }
                    }
//                    else mi = typeof( DataContextInterceptor ).GetMethod( call.MethodBase.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic );
                    else
                    {
                        mi = DataContextInterceptor.GetMethod( oldProvider.GetType(), call.MethodBase.Name, call.Args );

                        if ( mi != null )
                        {
                            try
                            {
                                return new ReturnMessage( mi.Invoke( oldProvider, call.Args ), null, 0, null, call );
                            }
                            catch ( TargetInvocationException e )
                            {
                                return new ReturnMessage( e.InnerException, call );
                            }
                        }
                    }

                    throw new NotImplementedException(
                        string.Format( "Method not found: {0}( {1} )",
                            call.MethodBase.Name,
                            string.Join( ", ", call.Args.Select( a => Convert.ToString( a ) ) ) ) );
                }

                throw new NotImplementedException();
            }

            public bool CanCastTo( Type fromType, object o )
            {
                return true;
            }

            public string TypeName
            {
                get { return this.GetType().Name; }
                set { }
            }
        }
    }

Hope this helps!

Here’s a great bit of news for users (victims? In love) of my WPF Chromium wrapper – the next version of Awesomium has it’s own official C# wrapper!  You can read all about it here Smile

DotNetKicks Image

UPDATE: Actually this thing has several uses, but rather than spend time listing them I’ll invite [polite] suggestions how it can be used… Smile

Here’s a small MVC extension method that looks useful, but might be totally redundant:

public static void RenderPartial<TModel, TProperty>( this HtmlHelper<TModel> helper, string partialViewName, Expression<Func<TModel, TProperty>> expression )
{
    var model = (TModel)helper.ViewData.Model;
    var childModel = expression.Compile()( model );
    var viewData = new ViewDataDictionary<TProperty>( childModel );
    viewData.TemplateInfo.HtmlFieldPrefix = ExpressionHelper.GetExpressionText( expression );

    helper.RenderPartial( partialViewName, childModel, viewData );
}

Basically it’s the same as the regular Html.RenderPartial but you can pass your model as an expression.  It’ll handle getting the field name prefixes etc. automatically.

I’m pretty sure the same thing can be achieved with Html.EditorFor and Html.DisplayFor (possibly with better performance too, depending on if they take the Compile() hit or not).  However I could be wrong, so I posted it anyway Smile

DotNetKicks Image

The new Xbox Live family pack is a great idea. Just be aware if you have existing Gamertags to add, you can only do that through a console (currently). You need to have all the profiles on the same console (temporarily; just a memory stick will do). Don’t be tempted to “Create Family Member” through the Family Center page at http://www.xbox.com :). Doing so will create new Gold accounts, which count against an annual add/remove limit on the pack. These don’t expire for a year 😦 The unfortunate solution is to cancel your Family Pack (which seems to temporarily return the accounts to Silver/Free status – ugh 😦 ), then re-buy it (making sure you chase up any remaining-time credit you may “lose” in the process).

Other than that, $99/year for 4 Gold accounts is a nice deal 🙂

Update 1: Canceling the pack isn’t a sure fix 😦 (they’re looking into it 🙂 ).
Update 2: Others with same issue – http://forums.xbox.com/34945194/ShowPost.aspx#34945194