WCF and the Cyclical Object Referencing Problem

by Moridin8 28. April 2008 20:10

As usual, when you need something done right, you sometimes just can not rely on MSDN or its forums, google or any form of current literature - or even a number of Microsoft employee's on my contact lists. 

Thats just the way of it sometimes.

What am I talking about? DataContractSerialization in WCF - in reference to the sometimes essential need to send cyclical object graphs across the wire.  WCF just does not support it.  At all - Something to do with an Xml Serialization standard or some such.  Which is fine in the general run of the mill situations involved with third party SOA services publically published - well... no, not in my oppinion... it's just not good enough.

But I digress.

Ok, some of you may be asking, "What do you mean by cyclical object graphs?",

Here is crude example:

[DataContract]
public class Example
{
    [DataMember]
    public Example MeMyselfAndI { get; set; }

    public Example()
    {
        this.MeMyselfAndI = this;
    }
}

Notice the (bad example) of the MeMyselfAndI property referencing itself?  When you serialize the object any serializer object will usually spit out an exception.

But wait...  Doesn't WCF use the DataContractSerializer class?  And doesn't that support cyclical object graphs?  Yes it does, which is great.  It's just that WCF doesn't generate the DataContractSerializer with the PreserveReferences feature enabled, which can be a major issue on services hosted in IIS that use the .svc files, and auto-generated client proxies and/or in situations where you have absolutely no choice but to use WCF configuration files - the M$ recommended route - and rightly so.

There are plenty of examples on the web demonstrating how to use the DataContractSerializer/PreserveReferences purely on the client (and only the client so far as I can find) when building your WCF client manually sans config.  This however only solves half of the problem because you just can not get the server to play the same way with these examples if you need cyclical object graphs returned, and the lack of a configuration support flies in the face of all reason.

MSDN is simply no help, neither are the forums, neither are a couple of highly skilled Microsoft employed architects I know.  *grin* they will choke when I send them the link to this.  I tend to enjoy these moments...

So, here is the solution... here is how to get WCF to support PreserveReferences... and still maintain the configurational aspect of WCF.

First, the server

The mechanics of WCF hosted in IIS involves the use of the well known '.svc' file.  Behind the scenes within WCF each page is generated within a factory that generates a ServiceHost instance.  The service host handles the requested calls to your service as well as all the appropriate discriptive information required during the lifetime of the service request. 

Usually, the ServiceHost is completely handled by the activation classes within the the ASP.NET model (Microsoft say it's handled by IIS... not true... but makes things easy to explain I suppose).  The ServiceHost contains all the information about the service contracts etc.  However, the ServiceHost isn't generally available under normal circumstances - and we need the ServiceHost.

So, to get access to the ServiceHost, we need to create our own ServiceHost factory and tell the '.svc' to it instead of the default factory supplied by WCF (code follows shortly).  To tell the '.svc' file to use the custom factory we do the following:

Remove the codebehind attribute and replace it with the Factory attribute thus...

<%@ ServiceHost Language="C#" Debug="true" Service="TestWCF.ManagerService" Factory="TestWCF.ManagerServiceHostFactory"  %>

Don't worry about what visual studio says about the Factory attribute not being valid, it is supported by WCF in the internal System.ServiceModel.Activation.ServiceParser class, which is more important.

The custom ServiceHostFactory, ServiceHost and a minor DataContactSerializer replacement are as follows:

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Description;
using System.Xml;

public class ManagerServiceHostFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, 
Uri[] baseAddresses) { ManagerServiceCustomHost customServiceHost
= new ManagerServiceCustomHost(serviceType, baseAddresses);


return customServiceHost; } } public class ManagerServiceCustomHost : ServiceHost { public ManagerServiceCustomHost(Type serviceType, params Uri[] baseAddresses) : base(serviceType, baseAddresses) { } protected override void ApplyConfiguration() { base.ApplyConfiguration(); RefPreserveDataContractSerializerOperationBehavior.Reconfigure
(base.ImplementedContracts["TestWCF.IManagerService"].Operations); } } public class RefPreserveDataContractSerializerOperationBehavior
: DataContractSerializerOperationBehavior { public static void Reconfigure(OperationDescriptionCollection odc) { foreach (OperationDescription oper in odc) { for (int i = 0; i < oper.Behaviors.Count; i++) { if (oper.Behaviors[i] is DataContractSerializerOperationBehavior) { DataContractSerializerOperationBehavior tmp
= oper.Behaviors[i]
as DataContractSerializerOperationBehavior; // replace out the DataContractSerializerOperationBehavior
// with our own...
RefPreserveDataContractSerializerOperationBehavior tmp2
= new RefPreserveDataContractSerializerOperationBehavior
(oper, tmp.DataContractFormatAttribute); tmp2.DataContractSurrogate = tmp.DataContractSurrogate; tmp2.IgnoreExtensionDataObject = tmp.IgnoreExtensionDataObject; tmp2.MaxItemsInObjectGraph = tmp.MaxItemsInObjectGraph; oper.Behaviors[i] = tmp2; break; } } } } public RefPreserveDataContractSerializerOperationBehavior
(OperationDescription operationDescription) : this(operationDescription, null) { } public RefPreserveDataContractSerializerOperationBehavior
(OperationDescription operation,
DataContractFormatAttribute
dataContractFormatAttribute
) : base(operation, dataContractFormatAttribute) { } public override XmlObjectSerializer CreateSerializer
(Type type, string name, string ns, IList<Type> knownTypes) { return CreateDataContractSerializer(type, name, ns, knownTypes); } private static XmlObjectSerializer CreateDataContractSerializer
(Type type, string name, string ns, IList<Type> knownTypes) { return CreateDataContractSerializer(type, name, ns, knownTypes); } public override XmlObjectSerializer CreateSerializer
(Type type, XmlDictionaryString name, XmlDictionaryString ns,
IList<Type> knownTypes) { return new DataContractSerializer
(type, name, ns, knownTypes, int.MaxValue,
false,
true /* PreserveReferences*/,
null); } }

You should notice in the DataContractSerializer the 'static void Reconfigure(OperationDescriptionCollection odc)' method.  This is what does the work to ensure that WCF gives us that nice cyclical reference feature we are after.  Also please notice the contructor parameters used in the CreateSerializer method (please see MSDN for more info).

[client work pending... need to eat... ;)]

(didn't get chance to complete.... sorry)

Tags: , , , , , , ,

Articles

The Interpreter Pattern - and Postfix Notation

by Moridin8 16. April 2008 20:24

The Interpreter Pattern

 

namespace ooppatterns
{
    using System;
    using System.Collections.Generic;

    internal class Program
    {
        private static void Main( string[] args )
        {
            string expression = "8 ++ 1 4 + N 200 * +";

            PostFixParser PFP = new PostFixParser( expression );

            Console.WriteLine( "'{0}' equals {1}", expression, PFP.Evaluate() );

            Console.ReadLine();
        }
    }

    interface IExpression
    {
        void Parse( Stack<double> s );
    }

    class PostFixParser
    {
        private List<IExpression> tokenList = new List<IExpression>();

        public PostFixParser( string s )
        {
            foreach ( string token in s.Split( ' ' ) )
                switch ( token )
                {
                    case "AND":
                    case "&&":
                        this.tokenList.Add( new LAnd() );
                        break;
                    case "!":
                        this.tokenList.Add( new LNot() );
                        break;
                    case "N":
                        this.tokenList.Add( new Neg() );
                        break;
                    case "OR":
                    case "||":
                        this.tokenList.Add( new LOr() );
                        break;
                    case "&":
                        this.tokenList.Add( new BAnd() );
                        break;
                    case "~":
                        this.tokenList.Add( new BNot() );
                        break;
                    case "|":
                        this.tokenList.Add( new BOr() );
                        break;
                    case "<>":
                    case "!=":
                        this.tokenList.Add( new NotEquals() );
                        break;
                    case "==":
                        this.tokenList.Add( new Equals() );
                        break;
                    case ">":
                        this.tokenList.Add( new GreaterThan() );
                        break;
                    case "<":
                        this.tokenList.Add( new LessThan() );
                        break;
                    case ">=":
                        this.tokenList.Add( new GreaterOrEqualThan() );
                        break;
                    case "<=":
                        this.tokenList.Add( new LessOrEqualThan() );
                        break;
                    case "+":
                        this.tokenList.Add( new Plus() );
                        break;
                    case "++":
                        this.tokenList.Add( new Inc() );
                        break;
                    case "-":
                        this.tokenList.Add( new Minus() );
                        break;
                    case "--":
                        this.tokenList.Add( new Dec() );
                        break;
                    case "*":
                        this.tokenList.Add( new Multiply() );
                        break;
                    case "/":
                        this.tokenList.Add( new Divide() );
                        break;
                    case "%":
                        this.tokenList.Add( new Modulus() );
                        break;
                    case "^":
                        this.tokenList.Add( new Power() );
                        break;
                    default:
                        this.tokenList.Add( new Number( double.Parse( token ) ) );
                        break;
                }
        }

        public double Evaluate()
        {
            Stack<double> evalStack = new Stack<double>();

            foreach ( IExpression e in this.tokenList )
                e.Parse( evalStack );

            return evalStack.Pop();
        }
    }


    // Mathmatical operators
    class Number : IExpression
    {
        private double number;

        public Number( double number )
        {
            this.number = number;
        }

        public void Parse( Stack<double> s )
        {
            s.Push( number );
        }
    }

    class Plus : IExpression
    {
        public void Parse( Stack<double> s )
        {
            s.Push( s.Pop() + s.Pop() );
        }
    }

    class Inc : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( ++tmp );
        }
    }

    class Dec : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( --tmp );
        }
    }

    class Minus : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() - tmp );
        }
    }

    class Multiply : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() * tmp );
        }
    }

    class Divide : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() / tmp );
        }
    }

    class Modulus : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() % tmp );
        }
    }

    class Power : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( Convert.ToInt32( Math.Pow( s.Pop(), tmp ) ) );
        }
    }

    // Equality operators
    class Equals : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() == tmp ? -1 : 0 );
        }
    }

    class NotEquals : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() == tmp ? 0 : -1 );
        }
    }

    class GreaterThan : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() > tmp ? -1 : 0 );
        }
    }

    class LessThan : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() < tmp ? 0 : -1 );
        }
    }

    class GreaterOrEqualThan : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() >= tmp ? -1 : 0 );
        }
    }

    class LessOrEqualThan : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double tmp = s.Pop();
            s.Push( s.Pop() <= tmp ? 0 : -1 );
        }
    }

    // Logical operators
    class LAnd : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double LHS = s.Pop();
            double RHS = s.Pop();

            if ( LHS < -1 || RHS < -1 || LHS > 0 || RHS > 0 )
                throw new InvalidOperationException();

            if ( LHS == RHS )
                s.Push( -1 );
            else
                s.Push( 0 );
        }
    }

    class LOr : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double LHS = s.Pop();
            double RHS = s.Pop();

            if ( LHS < -1 || RHS < -1 || LHS > 0 || RHS > 0 )
                throw new InvalidOperationException();

            if ( LHS == -1 || RHS == -1 )
                s.Push( -1 );
            else
                s.Push( 0 );
        }
    }

    class Neg : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double LHS = s.Pop();

            s.Push( -LHS );
        }
    }

    class LNot : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double LHS = s.Pop();

            if ( LHS < -1 || LHS > 0 )
                throw new InvalidOperationException();

            if ( LHS == -1 )
                s.Push( 0 );
            else
                s.Push( -1 );
        }
    }

    // Bitwise operators
    class BAnd : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double LHS = s.Pop();
            double RHS = s.Pop();

            s.Push( Convert.ToInt32(LHS) & Convert.ToInt32(RHS) );
        }
    }

    class BOr : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double LHS = s.Pop();
            double RHS = s.Pop();

            s.Push( Convert.ToInt32(LHS) | Convert.ToInt32(RHS) );
        }
    }

    class BNot : IExpression
    {
        public void Parse( Stack<double> s )
        {
            double LHS = s.Pop();

            s.Push( ~Convert.ToInt32(LHS) );
        }
    }
}
 

Tags: , ,

Articles

The Chain Pattern - and Infix Notation

by Moridin8 12. April 2008 20:20

[For a bod in ##csharp]

** In an attempt to try and make things a little more 'realistic' I have added a real example of the use of this pattern below the basic example given here. 

namespace ooppatterns
{
    using System;

    internal class Program
    {
        private static void Main( string[] args )
        {
            // Build responsibility chain
            MailRoom MR = new MailRoom();
            MR.Next = new SmallOrderDepartment();
            MR.Next.Next = new LargeOrderDepartment();
            MR.Next.Next.Next = new WarehouseOrderDepartment();

            // Process incomming mail...

            MR.ProcessRequest( new Mail( OrderType.CompanyOrder ) );

            Console.WriteLine( new string( '-', 60 ) );

            MR.ProcessRequest( new Mail( OrderType.WarehouseOrder ) );

            Console.WriteLine( new string( '-', 60 ) );

            MR.ProcessRequest( new Mail( OrderType.None ) );

            Console.WriteLine( new string( '-', 60 ) );

            MR.ProcessRequest( new Mail( OrderType.HomeOrder ) );

            Console.ReadLine();
        }
    }

    internal enum OrderType
    {
        None,
        HomeOrder,
        ProfessionalOrder,
        CompanyOrder,
        WarehouseOrder
    }

    class Mail
    {
        public OrderType Order;

        public Mail( OrderType order )
        {
            this.Order = order;
        }
    }

    abstract class Handler
    {
        private Handler _next;

        public Handler Next
        {
            get { return this._next; }
            set { this._next = value; }
        }

        public abstract void ProcessRequest( Mail letter );
    }

    // Handlers with specific Responsibility criteria...
    class MailRoom : Handler
    {
        public override void ProcessRequest( Mail letter )
        {
            if ( letter.Order == OrderType.None )
                Console.WriteLine( "Mis-mailed... MailRoom handles" );
            else if ( base.Next != null )
            {
                Console.WriteLine
( "MailRoom can not handle this. Passing along..." ); base.Next.ProcessRequest( letter ); } else Console.WriteLine( "Could not delegate order!" ); } } class SmallOrderDepartment : Handler { public override void ProcessRequest( Mail letter ) { if ( letter.Order == OrderType.HomeOrder
|| letter.Order == OrderType.ProfessionalOrder ) Console.WriteLine( "SmallOrderDepartment handled order" ); else if ( base.Next != null ) { Console.WriteLine( "SmallOrderDepartment can not handle this."
+ @" Passing along..."
); base.Next.ProcessRequest( letter ); } else Console.WriteLine( "Could not delegate order!" ); } } class LargeOrderDepartment : Handler { public override void ProcessRequest( Mail letter ) { if ( letter.Order == OrderType.CompanyOrder ) Console.WriteLine( "LargeOrderDepartment handled order" ); else if ( base.Next != null ) { Console.WriteLine( "LargeOrderDepartment can not handle this."
+ @" Passing along..."
); base.Next.ProcessRequest( letter ); } else Console.WriteLine( "Could not delegate order!" ); } } class WarehouseOrderDepartment : Handler { public override void ProcessRequest( Mail letter ) { if ( letter.Order == OrderType.WarehouseOrder ) Console.WriteLine( "WarehouseOrderDepartment handled order" ); else if ( base.Next != null ) { Console.WriteLine( "LargeOrderDepartment can not handle this."
+ @" Passing along..."
); base.Next.ProcessRequest( letter ); } else Console.WriteLine( "Could not delegate order!" ); } } }

InFix Notation Parser

I resurrected my InFix parser routine from my CMS code snippet library, removed a couple of things and presented for the site.  This is a prime example of the Chain pattern in use.  Please be aware of a few things though.

  1. The operator precedence method is just a dumb switch routine.  I removed the precedence parser because it wouldn't work after I removed the things I did for the example.  It is *not* fully tested.  It seems to work though.
  2. Due to the way that the partner PostFix routine works, negations are parsed to the character 'N'.
  3. The PostFix routine that partner's this example is the example I am using for the Interpreter Pattern.  Please feel free to meld the two.

Enjoy...

namespace ooppatterns
{
    using System;
    using System.Collections.Generic;
    using System.Text;

    internal class Program
    {
        private static void Main( string[] args )
        {
            string infix = "8++ + -(1+4) * -200";

            // Instantiate a parser package
            Package cont = new Package( infix );

            // Create InFixParser and chain responsibilities
            InFixParser IFP = new InFixParser();
            IFP.Next = new Number();
            IFP.Next.Next = new Parenthesis();
            IFP.Next.Next.Next = new Operators();
            IFP.Next.Next.Next.Next = new UnknownCharacters();

            // Parse
            IFP.Parse( cont );

            // Now take results from the PostFix queue and
            // convert to a string for viewing.
            StringBuilder SB = new StringBuilder();

            while ( cont.PostFix.Count > 0 )
                SB.Append( cont.PostFix.Dequeue() + " " );

            Console.WriteLine( SB.ToString() );

            Console.ReadLine();
        }

        // Infix parser package.  Holds all information pertinant
        // to the conversion of InFix to PostFix
        class Package
        {
            private Queue<string> _postFix = new Queue<string>();
            private Stack<string> _operator = new Stack<string>();
            private Stack<char> _unary = new Stack<char>();
            private int _parenthesis = 0;
            private bool _lastParsedAnOp = false;
            private string _infix;
            private int _i;

            public Package( string infix )
            {
                this._infix = infix;
            }

            public Queue<string> PostFix
            {
                get { return this._postFix; }
            }

            public Stack<string> Operator
            {
                get { return this._operator; }
            }

            public Stack<char> Unary
            {
                get { return this._unary; }
            }

            public int Parenthesis
            {
                get { return this._parenthesis; }
                set { this._parenthesis = value; }
            }

            public bool LastParsedAnOp
            {
                get { return this._lastParsedAnOp; }
                set { this._lastParsedAnOp = value; }
            }

            public void SkipNextChar()
            {
                this._i++;
            }

            public char ReadNextChar()
            {
                return this._infix[this._i++];
            }

            public char PeekNextChar()
            {
                if ( this.IsEOF )
                    return '\0';

                return this._infix[this._i];
            }

            public bool IsEOF
            {
                get { return !( this._i < this._infix.Length ); }
            }
        }

        abstract class Handler
        {
            private Handler _next;

            public Handler Next
            {
                get { return this._next; }
                set { this._next = value; }
            }

            public abstract void Parse( Package con );
        }

        class InFixParser : Handler
        {
            // this handler simply pushes tasks along the chain
            // and finishes the work left by the other links.
            public override void Parse( Package con )
            {
                while ( !con.IsEOF )
                    base.Next.Parse( con );

                // clear out operator stack...
                while ( con.Operator.Count > 0 )
                    con.PostFix.Enqueue( con.Operator.Pop().ToString() );
            }
        }

        class Number : Handler
        {
            // Handles numeric values
            public override void Parse( Package con )
            {
                char ch = con.PeekNextChar();

                if ( ( ch >= '0' && ch <= '9' ) || ch == '.' )
                {
                    List<char> tb = new List<char>();

                    // get the whole number
                    for ( ; ( ch >= '0' && ch <= '9' ) || ch == '.' || ch == '-';
                            ch = con.PeekNextChar()
                    )
                        tb.Add( con.ReadNextChar() );

                    // Handle negation
                    if ( con.Unary.Count != 0 && con.Parenthesis == 0 )
                    {
                        con.Unary.Pop();
                        con.PostFix.Enqueue( "N" + new String( tb.ToArray() ) );
                    }
                    else
                        con.PostFix.Enqueue( new String( tb.ToArray() ) );

                    con.LastParsedAnOp = false;
                }
                else if ( base.Next != null )
                    base.Next.Parse( con );
            }
        }

        class Parenthesis : Handler
        {
            // Handles any brackets (Parenthesis)
            public override void Parse( Package con )
            {
                char ch = con.PeekNextChar();

                if ( ch == '(' )
                {
                    con.Operator.Push( ch.ToString() );
                    con.Parenthesis++;
                    con.SkipNextChar();
                    con.LastParsedAnOp = false;
                }
                else if ( ch == ')' )
                {
                    while ( con.Operator.Count > 0 && ( con.Operator.Peek() ) != "(" )
                        con.PostFix.Enqueue( con.Operator.Pop().ToString() );

                    con.Operator.Pop();
                    con.Parenthesis--;

                    // place any unary operators in queue.
                    if ( con.Unary.Count > 0 )
                        con.PostFix.Enqueue( con.Unary.Pop().ToString() );

                    con.SkipNextChar();
                    con.LastParsedAnOp = false;
                }
                else if ( base.Next != null )
                    base.Next.Parse( con );
            }
        }

        class Operators : Handler
        {
            // handle operators
            public override void Parse( Package con )
            {
                char ch = con.PeekNextChar();

                if ( ( ch >= '%' && ch <= '/' || ch == '!' || ch == '~' ) 
                     && 
                     ch != '.' && ch != '(' && ch != ')' 
                )
                    if ( con.LastParsedAnOp || con.PostFix.Count == 0 )
                    {
                        // if this just previously handled an operator,
                        // then this one must be unary
                        if ( ch == '-' )
                            con.Unary.Push( 'N' );
                        else if ( Precedence( ch.ToString() ) == 90 )
                            con.Unary.Push( ch );
                        else
                            throw new InvalidOperationException();

                        con.SkipNextChar();
                        con.LastParsedAnOp = false;
                    }
                    else
                    {
                        // Process operator...
                        List<char> tb = new List<char>();

                        for ( ; tb.Count < 2 && ( ch >= '%' && ch <= '/' ) 
                                && ch != '.' && ch != '(' && ch != ')'; 
                                ch = con.PeekNextChar() 
                        )
                            tb.Add( con.ReadNextChar() );

                        string token = new String( tb.ToArray() );
                        string top = "";
                        int opPrecA = Precedence( token );

                        // handle post increment/decrement operators
                        if ( opPrecA == 100 )
                        {
                            con.PostFix.Enqueue( token );
                            return;
                        }

                        // Discover precedence of operator and sort stack accordingly.
                        //
                        // NB:  the precedence stack sorter is not fully tested!
// if ( con.Operator.Count > 0 ) top = con.Operator.Peek(); int opPrecB = Precedence( top ); if ( opPrecA > opPrecB ) con.Operator.Push( token ); else { while ( opPrecB >= opPrecA ) { string tmp = con.Operator.Pop(); top = con.Operator.Peek(); con.Operator.Push( tmp ); opPrecB = Precedence( top ); } con.Operator.Push( top ); } con.LastParsedAnOp = true; } else if ( base.Next != null ) base.Next.Parse( con ); } // Get operator precedence // NB: the precedence stack sorter is not fully tested! private static int Precedence( string ch ) { switch ( ch ) { case "++": case "--": return 100; case "!": case "~": return 90; case "*": case "/": case "%": case "^": case "&": case "|": return 80; case "+": case "-": return 70; case "<<": case ">>": return 60; case "<": case ">": case "<=": case ">=": return 40; case "==": case "!=": case "<>": return 30; case "&&": return 20; case "||": return 10; default: return 0; } } } class UnknownCharacters : Handler { // handle other characters (ignore) public override void Parse( Package con ) { con.SkipNextChar(); } } } }

Tags: , , , ,

Articles

Powered by BlogEngine.NET 1.5.0.7

About Matt R.Warren

MeMy name is Matt and I am the current tenant of this small corner of the internet. I mostly architect, design and prototype applications that use .NET with C# and a little C++/CLI for Enterprise although I am aware of and enjoy fully embracing Java based solutions and alternatives such as Mono/Linux.  

I have worked on projects ranging from small tools to large distributed real-time Enterprise systems ranging from EPOS and real-time/JIT stock management systems, to distributed applications for National/International Utility, Healthcare, Insurance and Finance  in the private sector in both the USA and the EU.

My LinkedIn Profile (Opens new window/tab)

“Matt is one of the brightest people I've worked with. His in-depth knowledge of the .NET frameworks has been a tremendous benefit to nVISIA and our clients. His knowledge of software architecture in general allows him to architect systems for the best fit to his client's needs.” 
Dan Christopherson , Technical Director , nVISIA

“I had the distinct pleasure of working with Matt at nVisia. Matt's understanding of the Microsoft Technical space is outstanding. He is constantly working on improving his technical skills and rapidly masters any new technology that he encounters. He is an excellent teacher and a wonderful asset for any size team.” 
Jim Harnden , Senior Technical Architect , nVISIA

“Matt Warren is a very talented developer with great capacity for self study, investigation and adapts to new languages and frameworks with ease. He has an excellent grasp of software architecture and modern development principles. He has proven himself time and time again to be a hard worker and someone who can get the job done when you're in a tight spot.” 
Andrew Jump , Partner, C# Developer , Contegra

This website represents some of my spare time.  My small presence on the web between my family and my career.  I hope over time you find many useful things here.