What Was I Thinking?

Follies & Foils of .NET Development

  Home  |   Contact  |   Syndication    |   Login
  41 Posts | 0 Stories | 97 Comments | 0 Trackbacks

News

Archives

Post Categories

Check These Out

Gurus

Saturday, October 10, 2009 #

Recently I had the need to implement support for Dynamic Linq queries in my framework project.  For the uninitiated, Dynamic Linq allows me to write statements like this:

var query =
               db.Customers.Where("City == @0 and Orders.Count >= @1", "London", 10).
               OrderBy("CompanyName").
               Select("New(CompanyName as Name, Phone)");

where I can specify the predicates and selectors as string values.   Microsoft has published a helper class that enables DynamicLinq support here -->C# Dynamic Query Library (included in the -LinqSamples-DynamicQuery directory).

 

Buried in this code is a class Called Dynamic.cs.  Include this code file into your project and you’ll have Dyanmic Linq support, Unless…

 

Unless, you’re developing a silverlight application.  The dynamic class makes use of a ReaderWriterLock class that isn’t available in the Silverlight implementation of System.Threading.

Using Reflector, I extracted the disassembled code for ReaderWriterLock and made a version that will compile and run under silverlight.  The only adjustment was commenting out the HostProtection attribute since it wasn’t available due to its protection level.  In my testing I haven’t run into any problems as the result of removing this attribute.

Here’s the code you’ll want to add to your silverlight libraries in order to allow the compilation of Dynamic.cs and support Dynamic Linq in your silverlight project:

 

ReaderWriterLock.cs

using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Security.Permissions;
using System;
//[ComVisible(true), HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
[ComVisible(true)]
public sealed class ReaderWriterLock : CriticalFinalizerObject
{
    // Fields
    private int _dwLLockID;
    private int _dwState;
    private int _dwULockID;
    private int _dwWriterID;
    private int _dwWriterSeqNum;
    private IntPtr _hObjectHandle;
    private IntPtr _hReaderEvent;
    private IntPtr _hWriterEvent;
    private short _wWriterLevel;
 
    // Methods
    public ReaderWriterLock()
    {
        this.PrivateInitialize();
    }
 
    public void AcquireReaderLock(int millisecondsTimeout)
    {
        this.AcquireReaderLockInternal(millisecondsTimeout);
    }
 
    public void AcquireReaderLock(TimeSpan timeout)
    {
        long totalMilliseconds = (long)timeout.TotalMilliseconds;
        if ((totalMilliseconds < -1L) || (totalMilliseconds > 0x7fffffffL))
        {
            throw new ArgumentOutOfRangeException("timeout", "ArgumentOutOfRange_NeedNonNegOrNegative1");
        }
        this.AcquireReaderLockInternal((int)totalMilliseconds);
    }
 
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void AcquireReaderLockInternal(int millisecondsTimeout);
    public void AcquireWriterLock(int millisecondsTimeout)
    {
        this.AcquireWriterLockInternal(millisecondsTimeout);
    }
 
    public void AcquireWriterLock(TimeSpan timeout)
    {
        long totalMilliseconds = (long)timeout.TotalMilliseconds;
        if ((totalMilliseconds < -1L) || (totalMilliseconds > 0x7fffffffL))
        {
            throw new ArgumentOutOfRangeException("timeout", "ArgumentOutOfRange_NeedNonNegOrNegative1");
        }
        this.AcquireWriterLockInternal((int)totalMilliseconds);
    }
 
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void AcquireWriterLockInternal(int millisecondsTimeout);
    [MethodImpl(MethodImplOptions.InternalCall)]
    public extern bool AnyWritersSince(int seqNum);
    public void DowngradeFromWriterLock(ref LockCookie lockCookie)
    {
        this.DowngradeFromWriterLockInternal(ref lockCookie);
    }
 
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void DowngradeFromWriterLockInternal(ref LockCookie lockCookie);
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void FCallReleaseLock(ref LockCookie result);
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void FCallUpgradeToWriterLock(ref LockCookie result, int millisecondsTimeout);
    ~ReaderWriterLock()
    {
        this.PrivateDestruct();
    }
 
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void PrivateDestruct();
    [MethodImpl(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    private extern bool PrivateGetIsReaderLockHeld();
    [MethodImpl(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    private extern bool PrivateGetIsWriterLockHeld();
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern int PrivateGetWriterSeqNum();
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void PrivateInitialize();
    public LockCookie ReleaseLock()
    {
        LockCookie result = new LockCookie();
        this.FCallReleaseLock(ref result);
        return result;
    }
 
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    public void ReleaseReaderLock()
    {
        this.ReleaseReaderLockInternal();
    }
 
    [MethodImpl(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    private extern void ReleaseReaderLockInternal();
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    public void ReleaseWriterLock()
    {
        this.ReleaseWriterLockInternal();
    }
 
    [MethodImpl(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    private extern void ReleaseWriterLockInternal();
    public void RestoreLock(ref LockCookie lockCookie)
    {
        this.RestoreLockInternal(ref lockCookie);
    }
 
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void RestoreLockInternal(ref LockCookie lockCookie);
    public LockCookie UpgradeToWriterLock(int millisecondsTimeout)
    {
        LockCookie result = new LockCookie();
        this.FCallUpgradeToWriterLock(ref result, millisecondsTimeout);
        return result;
    }
 
    public LockCookie UpgradeToWriterLock(TimeSpan timeout)
    {
        long totalMilliseconds = (long)timeout.TotalMilliseconds;
        if ((totalMilliseconds < -1L) || (totalMilliseconds > 0x7fffffffL))
        {
            throw new ArgumentOutOfRangeException("timeout","ArgumentOutOfRange_NeedNonNegOrNegative1");
        }
        return this.UpgradeToWriterLock((int)totalMilliseconds);
    }
 
    // Properties
    public bool IsReaderLockHeld
    {
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        get
        {
            return this.PrivateGetIsReaderLockHeld();
        }
    }
 
    public bool IsWriterLockHeld
    {
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        get
        {
            return this.PrivateGetIsWriterLockHeld();
        }
    }
 
    public int WriterSeqNum
    {
        get
        {
            return this.PrivateGetWriterSeqNum();
        }
    }
}
 

and LockCookie.cs

using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential), ComVisible(true)]
public struct LockCookie
{
    private int _dwFlags;
    private int _dwWriterSeqNum;
    private int _wReaderAndWriterLevel;
    private int _dwThreadID;
    public override int GetHashCode()
    {
        return (((this._dwFlags + this._dwWriterSeqNum) + this._wReaderAndWriterLevel) + this._dwThreadID);
    }
 
    public override bool Equals(object obj)
    {
        return ((obj is LockCookie) && this.Equals((LockCookie)obj));
    }
 
    public bool Equals(LockCookie obj)
    {
        return ((((obj._dwFlags == this._dwFlags) && (obj._dwWriterSeqNum == this._dwWriterSeqNum)) && (obj._wReaderAndWriterLevel == this._wReaderAndWriterLevel)) && (obj._dwThreadID == this._dwThreadID));
    }
 
    public static bool operator ==(LockCookie a, LockCookie b)
    {
        return a.Equals(b);
    }
 
    public static bool operator !=(LockCookie a, LockCookie b)
    {
        return !(a == b);
    }
}
 
 

 

and ReliabilityContract.cs

using System;
[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Assembly, Inherited = false)]
public sealed class ReliabilityContractAttribute : Attribute
{
// Fields
private Cer _cer;
private Consistency _consistency;

// Methods
public ReliabilityContractAttribute(Consistency consistencyGuarantee, Cer cer)
{
this._consistency = consistencyGuarantee;
this._cer = cer;
}

// Properties
public Cer Cer
{
get
{
return this._cer;
}
}

public Consistency ConsistencyGuarantee
{
get
{
return this._consistency;
}
}
}
public enum Consistency
{
MayCorruptProcess,
MayCorruptAppDomain,
MayCorruptInstance,
WillNotCorruptState
}


public enum Cer
{
None,
MayFail,
Success
}