public GetClrArgumentType ( int index ) : |
||
index | int | |
Résultat |
/// <summary> /// Get a late-bound extension object from the external argument list. Bind to a method on the object and invoke it, /// passing "args" as arguments. /// </summary> public IList <XPathItem> InvokeXsltLateBoundFunction(string name, string namespaceUri, IList <XPathItem>[] args) { object instance; object[] objActualArgs; XmlQueryType xmlTypeFormalArg; Type clrTypeFormalArg; object objRet; // Get external object instance from argument list (throw if either the list or the instance doesn't exist) instance = (_argList != null) ? _argList.GetExtensionObject(namespaceUri) : null; if (instance == null) { throw new XslTransformException(SR.XmlIl_UnknownExtObj, namespaceUri); } // Bind to a method on the instance object if (_extFuncsLate == null) { _extFuncsLate = new XmlExtensionFunctionTable(); } // Bind to the instance, looking for a matching method (throws if no matching method) XmlExtensionFunction extFunc = _extFuncsLate.Bind(name, namespaceUri, args.Length, instance.GetType(), XmlQueryRuntime.LateBoundFlags); // Create array which will contain the actual arguments objActualArgs = new object[args.Length]; for (int i = 0; i < args.Length; i++) { // 1. Assume that the input value can only have one of the following 5 Xslt types: // xs:double, xs:string, xs:boolean, node* (can be rtf) // 2. Convert each Rtf value to a NodeSet containing one node. Now the value may only have one of the 4 Xslt types. // 3. Convert from one of the 4 Xslt internal types to the Xslt internal type which is closest to the formal // argument's Xml type (inferred from the Clr type of the formal argument). xmlTypeFormalArg = extFunc.GetXmlArgumentType(i); switch (xmlTypeFormalArg.TypeCode) { case XmlTypeCode.Boolean: objActualArgs[i] = XsltConvert.ToBoolean(args[i]); break; case XmlTypeCode.Double: objActualArgs[i] = XsltConvert.ToDouble(args[i]); break; case XmlTypeCode.String: objActualArgs[i] = XsltConvert.ToString(args[i]); break; case XmlTypeCode.Node: if (xmlTypeFormalArg.IsSingleton) { objActualArgs[i] = XsltConvert.ToNode(args[i]); } else { objActualArgs[i] = XsltConvert.ToNodeSet(args[i]); } break; case XmlTypeCode.Item: objActualArgs[i] = args[i]; break; default: Debug.Fail("This XmlTypeCode should never be inferred from a Clr type: " + xmlTypeFormalArg.TypeCode); break; } // 4. Change the Clr representation to the Clr type of the formal argument clrTypeFormalArg = extFunc.GetClrArgumentType(i); if (xmlTypeFormalArg.TypeCode == XmlTypeCode.Item || !clrTypeFormalArg.IsAssignableFrom(objActualArgs[i].GetType())) { objActualArgs[i] = _runtime.ChangeTypeXsltArgument(xmlTypeFormalArg, objActualArgs[i], clrTypeFormalArg); } } // 1. Invoke the late bound method objRet = extFunc.Invoke(instance, objActualArgs); // 2. Convert to IList<XPathItem> if (objRet == null && extFunc.ClrReturnType == XsltConvert.VoidType) { return(XmlQueryNodeSequence.Empty); } return((IList <XPathItem>)_runtime.ChangeTypeXsltResult(XmlQueryTypeFactory.ItemS, objRet)); }
/// <summary> /// Generate code for for QilNodeType.XsltInvokeEarlyBound. /// </summary> protected override QilNode VisitXsltInvokeEarlyBound(QilInvokeEarlyBound ndInvoke) { QilName ndName = ndInvoke.Name; XmlExtensionFunction extFunc; Type clrTypeRetSrc, clrTypeRetDst; // Retrieve metadata from the extension function extFunc = new XmlExtensionFunction(ndName.LocalName, ndName.NamespaceUri, ndInvoke.ClrMethod); clrTypeRetSrc = extFunc.ClrReturnType; clrTypeRetDst = GetStorageType(ndInvoke); // Prepare to call runtime.ChangeTypeXsltResult if (clrTypeRetSrc != clrTypeRetDst && !ndInvoke.XmlType.IsEmpty) { _helper.LoadQueryRuntime(); _helper.LoadInteger(_helper.StaticData.DeclareXmlType(ndInvoke.XmlType)); } // If this is not a static method, then get the instance object if (!extFunc.Method.IsStatic) { // Special-case the XsltLibrary object if (ndName.NamespaceUri.Length == 0) _helper.LoadXsltLibrary(); else _helper.CallGetEarlyBoundObject(_helper.StaticData.DeclareEarlyBound(ndName.NamespaceUri, extFunc.Method.DeclaringType), extFunc.Method.DeclaringType); } // Generate code to push each Invoke argument onto the stack for (int iArg = 0; iArg < ndInvoke.Arguments.Count; iArg++) { QilNode ndActualArg; XmlQueryType xmlTypeFormalArg; Type clrTypeActualArg, clrTypeFormalArg; ndActualArg = ndInvoke.Arguments[iArg]; // Infer Xml type and Clr type of formal argument xmlTypeFormalArg = extFunc.GetXmlArgumentType(iArg); clrTypeFormalArg = extFunc.GetClrArgumentType(iArg); Debug.Assert(ndActualArg.XmlType.IsSubtypeOf(xmlTypeFormalArg), "Xml type of actual arg must be a subtype of the Xml type of the formal arg"); // Use different conversion rules for internal Xslt libraries. If the actual argument is // stored using Clr type T, then library must use type T, XPathItem, IList<T>, or IList<XPathItem>. // If the actual argument is stored using Clr type IList<T>, then library must use type // IList<T> or IList<XPathItem>. This is to ensure that there will not be unnecessary // conversions that take place when calling into an internal library. if (ndName.NamespaceUri.Length == 0) { Type itemType = GetItemStorageType(ndActualArg); if (clrTypeFormalArg == XmlILMethods.StorageMethods[itemType].IListType) { // Formal type is IList<T> NestedVisitEnsureStack(ndActualArg, itemType, true); } else if (clrTypeFormalArg == XmlILMethods.StorageMethods[typeof(XPathItem)].IListType) { // Formal type is IList<XPathItem> NestedVisitEnsureStack(ndActualArg, typeof(XPathItem), true); } else if ((ndActualArg.XmlType.IsSingleton && clrTypeFormalArg == itemType) || ndActualArg.XmlType.TypeCode == XmlTypeCode.None) { // Formal type is T NestedVisitEnsureStack(ndActualArg, clrTypeFormalArg, false); } else if (ndActualArg.XmlType.IsSingleton && clrTypeFormalArg == typeof(XPathItem)) { // Formal type is XPathItem NestedVisitEnsureStack(ndActualArg, typeof(XPathItem), false); } else Debug.Fail("Internal Xslt library may not use parameters of type " + clrTypeFormalArg); } else { // There is an implicit upcast to the Xml type of the formal argument. This can change the Clr storage type. clrTypeActualArg = GetStorageType(xmlTypeFormalArg); // If the formal Clr type is typeof(object) or if it is not a supertype of the actual Clr type, then call ChangeTypeXsltArgument if (xmlTypeFormalArg.TypeCode == XmlTypeCode.Item || !clrTypeFormalArg.IsAssignableFrom(clrTypeActualArg)) { // (clrTypeFormalArg) runtime.ChangeTypeXsltArgument(xmlTypeFormalArg, (object) value, clrTypeFormalArg); _helper.LoadQueryRuntime(); _helper.LoadInteger(_helper.StaticData.DeclareXmlType(xmlTypeFormalArg)); NestedVisitEnsureStack(ndActualArg, GetItemStorageType(xmlTypeFormalArg), !xmlTypeFormalArg.IsSingleton); _helper.TreatAs(clrTypeActualArg, typeof(object)); _helper.LoadType(clrTypeFormalArg); _helper.Call(XmlILMethods.ChangeTypeXsltArg); _helper.TreatAs(typeof(object), clrTypeFormalArg); } else { NestedVisitEnsureStack(ndActualArg, GetItemStorageType(xmlTypeFormalArg), !xmlTypeFormalArg.IsSingleton); } } } // Invoke the target method _helper.Call(extFunc.Method); // Return value is on the stack; convert it to canonical ILGen storage type if (ndInvoke.XmlType.IsEmpty) { _helper.Emit(OpCodes.Ldsfld, XmlILMethods.StorageMethods[typeof(XPathItem)].SeqEmpty); } else if (clrTypeRetSrc != clrTypeRetDst) { // (T) runtime.ChangeTypeXsltResult(idxType, (object) value); _helper.TreatAs(clrTypeRetSrc, typeof(object)); _helper.Call(XmlILMethods.ChangeTypeXsltResult); _helper.TreatAs(typeof(object), clrTypeRetDst); } else if (ndName.NamespaceUri.Length != 0 && !clrTypeRetSrc.GetTypeInfo().IsValueType) { // Check for null if a user-defined extension function returns a reference type Label lblSkip = _helper.DefineLabel(); _helper.Emit(OpCodes.Dup); _helper.Emit(OpCodes.Brtrue, lblSkip); _helper.LoadQueryRuntime(); _helper.Emit(OpCodes.Ldstr, SR.Xslt_ItemNull); _helper.Call(XmlILMethods.ThrowException); _helper.MarkLabel(lblSkip); } _iterCurr.Storage = StorageDescriptor.Stack(GetItemStorageType(ndInvoke), !ndInvoke.XmlType.IsSingleton); return ndInvoke; }