XmlExtensionFunction.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / XmlUtils / System / Xml / Xsl / Runtime / XmlExtensionFunction.cs / 1305376 / XmlExtensionFunction.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
using System; 
using System.Collections.Generic; 
using System.Xml;
using System.Xml.Schema; 
using System.Reflection;
using System.Globalization;
using System.Diagnostics;
 
namespace System.Xml.Xsl.Runtime {
    using Res           = System.Xml.Utils.Res; 
 
    /// 
    /// Table of bound extension functions.  Once an extension function is bound and entered into the table, future bindings 
    /// will be very fast.  This table is not thread-safe.
    /// 
    internal class XmlExtensionFunctionTable {
        private Dictionary table; 
        private XmlExtensionFunction funcCached;
 
        public XmlExtensionFunctionTable() { 
            this.table = new Dictionary();
        } 

        public XmlExtensionFunction Bind(string name, string namespaceUri, int numArgs, Type objectType, BindingFlags flags) {
            XmlExtensionFunction func;
 
            if (this.funcCached == null)
                this.funcCached = new XmlExtensionFunction(); 
 
            // If the extension function already exists in the table, then binding has already been performed
            this.funcCached.Init(name, namespaceUri, numArgs, objectType, flags); 
            if (!this.table.TryGetValue(this.funcCached, out func)) {
                // Function doesn't exist, so bind it and enter it into the table
                func = this.funcCached;
                this.funcCached = null; 

                func.Bind(); 
                this.table.Add(func, func); 
            }
 
            return func;
        }
    }
 
    /// 
    /// This internal class contains methods that allow binding to extension functions and invoking them. 
    ///  
    internal class XmlExtensionFunction {
        private string namespaceUri;                // Extension object identifier 
        private string name;                        // Name of this method
        private int numArgs;                        // Argument count
        private Type objectType;                    // Type of the object which will be searched for matching methods
        private BindingFlags flags;                 // Modifiers that were used to search for a matching signature 
        private int hashCode;                       // Pre-computed hashcode
 
        private MethodInfo meth;                    // MethodInfo for extension function 
        private Type[] argClrTypes;                 // Type array for extension function arguments
        private Type retClrType;                    // Type for extension function return value 
        private XmlQueryType[] argXmlTypes;         // XmlQueryType array for extension function arguments
        private XmlQueryType retXmlType;            // XmlQueryType for extension function return value

        ///  
        /// Constructor.
        ///  
        public XmlExtensionFunction() { 
        }
 
        /// 
        /// Constructor (directly binds to passed MethodInfo).
        /// 
        public XmlExtensionFunction(string name, string namespaceUri, MethodInfo meth) { 
            this.name = name;
            this.namespaceUri = namespaceUri; 
            Bind(meth); 
        }
 
        /// 
        /// Constructor.
        /// 
        public XmlExtensionFunction(string name, string namespaceUri, int numArgs, Type objectType, BindingFlags flags) { 
            Init(name, namespaceUri, numArgs, objectType, flags);
        } 
 
        /// 
        /// Initialize, but do not bind. 
        /// 
        public void Init(string name, string namespaceUri, int numArgs, Type objectType, BindingFlags flags) {
            this.name = name;
            this.namespaceUri = namespaceUri; 
            this.numArgs = numArgs;
            this.objectType = objectType; 
            this.flags = flags; 
            this.meth = null;
            this.argClrTypes = null; 
            this.retClrType = null;
            this.argXmlTypes = null;
            this.retXmlType = null;
 
            // Compute hash code so that it is not recomputed each time GetHashCode() is called
            this.hashCode = namespaceUri.GetHashCode() ^ name.GetHashCode() ^ ((int) flags << 16) ^ (int) numArgs; 
        } 

        ///  
        /// Once Bind has been successfully called, Method will be non-null.
        /// 
        public MethodInfo Method {
            get { return this.meth; } 
        }
 
        ///  
        /// Once Bind has been successfully called, the Clr type of each argument can be accessed.
        /// Note that this may be different than Method.GetParameterInfo().ParameterType. 
        /// 
        public Type GetClrArgumentType(int index) {
            return this.argClrTypes[index];
        } 

        ///  
        /// Once Bind has been successfully called, the Clr type of the return value can be accessed. 
        /// Note that this may be different than Method.GetParameterInfo().ReturnType.
        ///  
        public Type ClrReturnType {
            get { return this.retClrType; }
        }
 
        /// 
        /// Once Bind has been successfully called, the inferred Xml types of the arguments can be accessed. 
        ///  
        public XmlQueryType GetXmlArgumentType(int index) {
            return this.argXmlTypes[index]; 
        }

        /// 
        /// Once Bind has been successfully called, the inferred Xml type of the return value can be accessed. 
        /// 
        public XmlQueryType XmlReturnType { 
            get { return this.retXmlType; } 
        }
 
        /// 
        /// Return true if the CLR type specified in the Init() call has a matching method.
        /// 
        public bool CanBind() { 
            MethodInfo[] methods = this.objectType.GetMethods(this.flags);
            bool ignoreCase = (this.flags & BindingFlags.IgnoreCase) != 0; 
            StringComparison comparison = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; 

            // Find method in object type 
            foreach (MethodInfo methSearch in methods) {
                if (methSearch.Name.Equals(this.name, comparison) && (this.numArgs == -1 || methSearch.GetParameters().Length == this.numArgs)) {
                    // Binding to generic methods will never succeed
                    if (!methSearch.IsGenericMethodDefinition) 
                        return true;
                } 
            } 

            return false; 
        }

        /// 
        /// Bind to the CLR type specified in the Init() call.  If a matching method cannot be found, throw an exception. 
        /// 
        public void Bind() { 
            MethodInfo[] methods = this.objectType.GetMethods(this.flags); 
            MethodInfo methMatch = null;
            bool ignoreCase = (this.flags & BindingFlags.IgnoreCase) != 0; 
            StringComparison comparison = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;

            // Find method in object type
            foreach (MethodInfo methSearch in methods) { 
                if (methSearch.Name.Equals(this.name, comparison) && (this.numArgs == -1 || methSearch.GetParameters().Length == this.numArgs)) {
                    if (methMatch != null) 
                        throw new XslTransformException(/*[XT_037]*/Res.XmlIl_AmbiguousExtensionMethod, this.namespaceUri, this.name, this.numArgs.ToString(CultureInfo.InvariantCulture)); 

                    methMatch = methSearch; 
                }
            }

            if (methMatch == null) { 
                methods = this.objectType.GetMethods(this.flags | BindingFlags.NonPublic);
                foreach (MethodInfo methSearch in methods) { 
                    if (methSearch.Name.Equals(this.name, comparison) && methSearch.GetParameters().Length == this.numArgs) 
                        throw new XslTransformException(/*[XT_038]*/Res.XmlIl_NonPublicExtensionMethod, this.namespaceUri, this.name);
                } 
                throw new XslTransformException(/*[XT_039]*/Res.XmlIl_NoExtensionMethod, this.namespaceUri, this.name, this.numArgs.ToString(CultureInfo.InvariantCulture));
            }

            if (methMatch.IsGenericMethodDefinition) 
                throw new XslTransformException(/*[XT_040]*/Res.XmlIl_GenericExtensionMethod, this.namespaceUri, this.name);
 
            Debug.Assert(methMatch.ContainsGenericParameters == false); 

            Bind(methMatch); 
        }

        /// 
        /// Bind to the specified MethodInfo. 
        /// 
        private void Bind(MethodInfo meth) { 
            ParameterInfo[] paramInfo = meth.GetParameters(); 
            int i;
 
            // Save the MethodInfo
            this.meth = meth;

            // Get the Clr type of each parameter 
            this.argClrTypes = new Type[paramInfo.Length];
            for (i = 0; i < paramInfo.Length; i++) 
                this.argClrTypes[i] = GetClrType(paramInfo[i].ParameterType); 

            // Get the Clr type of the return value 
            this.retClrType = GetClrType(this.meth.ReturnType);

            // Infer an Xml type for each Clr type
            this.argXmlTypes = new XmlQueryType[paramInfo.Length]; 
            for (i = 0; i < paramInfo.Length; i++) {
                this.argXmlTypes[i] = InferXmlType(this.argClrTypes[i]); 
 
                //
 



 

                if (this.namespaceUri.Length == 0) { 
                    if ((object) this.argXmlTypes[i] == (object) XmlQueryTypeFactory.NodeNotRtf) 
                        this.argXmlTypes[i] = XmlQueryTypeFactory.Node;
                    else if ((object) this.argXmlTypes[i] == (object) XmlQueryTypeFactory.NodeSDod) 
                        this.argXmlTypes[i] = XmlQueryTypeFactory.NodeS;
                }
                else {
                    if ((object) this.argXmlTypes[i] == (object) XmlQueryTypeFactory.NodeSDod) 
                        this.argXmlTypes[i] = XmlQueryTypeFactory.NodeNotRtfS;
                } 
            } 

            // Infer an Xml type for the return Clr type 
            this.retXmlType = InferXmlType(this.retClrType);
        }

        ///  
        /// Convert the incoming arguments to an array of CLR objects, and then invoke the external function on the "extObj" object instance.
        ///  
        public object Invoke(object extObj, object[] args) { 
            Debug.Assert(this.meth != null, "Must call Bind() before calling Invoke.");
            Debug.Assert(args.Length == this.argClrTypes.Length, "Mismatched number of actual and formal arguments."); 

            try {
                return this.meth.Invoke(extObj, this.flags, null, args, CultureInfo.InvariantCulture);
            } 
            catch (TargetInvocationException e) {
                throw new XslTransformException(e.InnerException, Res.XmlIl_ExtensionError, this.name); 
            } 
            catch (Exception e) {
                if (!XmlException.IsCatchableException(e)) { 
                    throw;
                }
                throw new XslTransformException(e, Res.XmlIl_ExtensionError, this.name);
            } 
        }
 
        ///  
        /// Return true if this XmlExtensionFunction has the same values as another XmlExtensionFunction.
        ///  
        public override bool Equals(object other) {
            XmlExtensionFunction that = other as XmlExtensionFunction;
            Debug.Assert(that != null);
 
            // Compare name, argument count, object type, and binding flags
            return (this.hashCode == that.hashCode && this.name == that.name && this.namespaceUri == that.namespaceUri && 
                    this.numArgs == that.numArgs && this.objectType == that.objectType && this.flags == that.flags); 
        }
 
        /// 
        /// Return this object's hash code, previously computed for performance.
        /// 
        public override int GetHashCode() { 
            return this.hashCode;
        } 
 
        /// 
        /// 1. Map enumerations to the underlying integral type. 
        /// 2. Throw an exception if the type is ByRef
        /// 
        private Type GetClrType(Type clrType) {
            if (clrType.IsEnum) 
                return Enum.GetUnderlyingType(clrType);
 
            if (clrType.IsByRef) 
                throw new XslTransformException(/*[XT_050]*/Res.XmlIl_ByRefType, this.namespaceUri, this.name);
 
            return clrType;
        }

        ///  
        /// Infer an Xml type from a Clr type using Xslt infererence rules
        ///  
        private XmlQueryType InferXmlType(Type clrType) { 
            return XsltConvert.InferXsltType(clrType);
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK