Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Web.Services / System / Web / Services / Protocols / LogicalMethodInfo.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="LogicalMethodInfo.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>                                                                
5 //------------------------------------------------------------------------------
6
7 namespace System.Web.Services.Protocols {
8
9     using System;
10     using System.Web.Services;
11     using System.Reflection;
12     using System.Collections;
13     using System.Security.Permissions;
14     using System.Globalization;
15     using System.Text;
16     using System.Security.Cryptography;
17
18     /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodTypes"]/*' />
19     /// <devdoc>
20     ///    <para>[To be supplied.]</para>
21     /// </devdoc>
22     public enum LogicalMethodTypes {
23         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodTypes.Sync"]/*' />
24         /// <devdoc>
25         ///    <para>[To be supplied.]</para>
26         /// </devdoc>
27         Sync = 0x1,
28         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodTypes.Async"]/*' />
29         /// <devdoc>
30         ///    <para>[To be supplied.]</para>
31         /// </devdoc>
32         Async = 0x2,
33     }
34
35
36     /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo"]/*' />
37     /// <devdoc>
38     ///    <para>[To be supplied.]</para>
39     /// </devdoc>
40     public sealed class LogicalMethodInfo {
41         MethodInfo methodInfo;
42         MethodInfo endMethodInfo;
43         ParameterInfo[] inParams;
44         ParameterInfo[] outParams;
45         ParameterInfo[] parameters;
46         Hashtable attributes;
47         Type retType;
48         ParameterInfo callbackParam;
49         ParameterInfo stateParam;
50         ParameterInfo resultParam;
51         string methodName;
52         bool isVoid;
53         static object[] emptyObjectArray = new object[0];
54         WebServiceBindingAttribute binding;
55         WebMethodAttribute attribute;
56         MethodInfo declaration;
57         static HashAlgorithm hash;
58
59         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.LogicalMethodInfo"]/*' />
60         /// <devdoc>
61         ///    <para>[To be supplied.]</para>
62         /// </devdoc>
63         public LogicalMethodInfo(MethodInfo methodInfo) : this (methodInfo, null) {
64         }
65
66         internal LogicalMethodInfo(MethodInfo methodInfo, WebMethod webMethod) {
67             if (methodInfo.IsStatic) throw new InvalidOperationException(Res.GetString(Res.WebMethodStatic, methodInfo.Name));
68             this.methodInfo = methodInfo;
69             if (webMethod != null) {
70                 this.binding = webMethod.binding;
71                 this.attribute = webMethod.attribute;
72                 this.declaration = webMethod.declaration;
73             }
74
75             MethodInfo methodDefinition = declaration != null ? declaration : methodInfo;
76             parameters = methodDefinition.GetParameters();
77             inParams = GetInParameters(methodDefinition, parameters, 0, parameters.Length, false);
78             outParams = GetOutParameters(methodDefinition, parameters, 0, parameters.Length, false);
79             retType = methodDefinition.ReturnType;
80             isVoid = retType == typeof(void);
81             methodName = methodDefinition.Name;
82             attributes = new Hashtable();
83         }
84
85         LogicalMethodInfo(MethodInfo beginMethodInfo, MethodInfo endMethodInfo, WebMethod webMethod) {
86             this.methodInfo = beginMethodInfo;
87             this.endMethodInfo = endMethodInfo;
88             methodName = beginMethodInfo.Name.Substring(5);
89             if (webMethod != null) {
90                 this.binding = webMethod.binding;
91                 this.attribute = webMethod.attribute;
92                 this.declaration = webMethod.declaration;
93             }
94             ParameterInfo[] beginParamInfos = beginMethodInfo.GetParameters();
95             if (beginParamInfos.Length < 2 ||
96                 beginParamInfos[beginParamInfos.Length - 1].ParameterType != typeof(object) ||
97                 beginParamInfos[beginParamInfos.Length - 2].ParameterType != typeof(AsyncCallback)) {
98                 throw new InvalidOperationException(Res.GetString(Res.WebMethodMissingParams, beginMethodInfo.DeclaringType.FullName, beginMethodInfo.Name, 
99                     typeof(AsyncCallback).FullName, typeof(object).FullName));
100             }
101
102             stateParam = beginParamInfos[beginParamInfos.Length - 1];
103             callbackParam = beginParamInfos[beginParamInfos.Length - 2];
104
105             inParams = GetInParameters(beginMethodInfo, beginParamInfos, 0, beginParamInfos.Length - 2, true);
106
107             ParameterInfo[] endParamInfos = endMethodInfo.GetParameters();
108             resultParam = endParamInfos[0];
109             outParams = GetOutParameters(endMethodInfo, endParamInfos, 1, endParamInfos.Length - 1, true);
110
111             parameters = new ParameterInfo[inParams.Length + outParams.Length];
112             inParams.CopyTo(parameters, 0);
113             outParams.CopyTo(parameters, inParams.Length);
114
115             retType = endMethodInfo.ReturnType;
116             isVoid = retType == typeof(void);
117             attributes = new Hashtable();
118         }
119
120         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.ToString"]/*' />
121         /// <devdoc>
122         ///    <para>[To be supplied.]</para>
123         /// </devdoc>
124         public override string ToString() {
125             return methodInfo.ToString();
126         }
127
128         // This takes in parameters, and returns return value followed by out parameters in an array
129         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.Invoke"]/*' />
130         /// <devdoc>
131         ///    <para>[To be supplied.]</para>
132         /// </devdoc>
133         [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
134         public object[] Invoke(object target, object[] values) {
135             if (outParams.Length > 0) {
136                 object[] newValues = new object[parameters.Length];
137                 for (int i = 0; i < inParams.Length; i++) {
138                     newValues[inParams[i].Position] = values[i];
139                 }
140                 values = newValues;
141             }
142             object returnValue = methodInfo.Invoke(target, values);
143             if (outParams.Length > 0) {
144                 int count = outParams.Length;
145                 if (!isVoid) count++;
146                 object[] results = new object[count];
147                 count = 0;
148                 if (!isVoid) results[count++] = returnValue;
149                 for (int i = 0; i < outParams.Length; i++) {
150                     results[count++] = values[outParams[i].Position];
151                 }
152                 return results;
153             }
154             else if (isVoid) {
155                 return emptyObjectArray;
156             }
157             else {
158                 return new object[] { returnValue };
159             }
160         }
161
162         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.BeginInvoke"]/*' />
163         /// <devdoc>
164         ///    <para>[To be supplied.]</para>
165         /// </devdoc>
166         [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
167         public IAsyncResult BeginInvoke(object target, object[] values, AsyncCallback callback, object asyncState) {
168             object[] asyncValues = new object[values.Length + 2];
169             values.CopyTo(asyncValues, 0);
170             asyncValues[values.Length] = callback;
171             asyncValues[values.Length + 1] = asyncState;
172             return (IAsyncResult)methodInfo.Invoke(target, asyncValues);
173         }
174
175         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.EndInvoke"]/*' />
176         /// <devdoc>
177         ///    <para>[To be supplied.]</para>
178         /// </devdoc>
179         [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
180         public object[] EndInvoke(object target, IAsyncResult asyncResult) {
181             object[] values = new object[outParams.Length + 1];
182             values[0] = asyncResult;
183             object returnValue = endMethodInfo.Invoke(target, values);
184             if (!isVoid) {
185                 values[0] = returnValue;
186                 return values;
187             }
188             else if (outParams.Length > 0) {
189                 object[] newValues = new object[outParams.Length];
190                 Array.Copy(values, 1, newValues, 0, newValues.Length);
191                 return newValues;
192             }
193             else {
194                 return emptyObjectArray;
195             }
196         }
197
198         internal WebServiceBindingAttribute Binding {
199             get { return binding; }
200         }
201
202         internal MethodInfo Declaration {
203             get { return declaration; }
204         }
205
206         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.DeclaringType"]/*' />
207         /// <devdoc>
208         ///    <para>[To be supplied.]</para>
209         /// </devdoc>
210         public Type DeclaringType {
211             get { return methodInfo.DeclaringType; }
212         }
213
214         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.Name"]/*' />
215         /// <devdoc>
216         ///    <para>[To be supplied.]</para>
217         /// </devdoc>
218         public string Name {
219             get { return methodName; }
220         }
221
222         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.AsyncResultParameter"]/*' />
223         /// <devdoc>
224         ///    <para>[To be supplied.]</para>
225         /// </devdoc>
226         public ParameterInfo AsyncResultParameter {
227             get { return resultParam; }
228         }
229
230         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.AsyncCallbackParameter"]/*' />
231         /// <devdoc>
232         ///    <para>[To be supplied.]</para>
233         /// </devdoc>
234         public ParameterInfo AsyncCallbackParameter {
235             get { return callbackParam; }
236         }
237
238         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.AsyncStateParameter"]/*' />
239         /// <devdoc>
240         ///    <para>[To be supplied.]</para>
241         /// </devdoc>
242         public ParameterInfo AsyncStateParameter {
243             get { return stateParam; }
244         }
245
246         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.ReturnType"]/*' />
247         /// <devdoc>
248         ///    <para>[To be supplied.]</para>
249         /// </devdoc>
250         public Type ReturnType {
251             get { return retType; }
252         }
253
254         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.IsVoid"]/*' />
255         /// <devdoc>
256         ///    <para>[To be supplied.]</para>
257         /// </devdoc>
258         public bool IsVoid {
259             get { return isVoid; }
260         }
261
262         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.IsAsync"]/*' />
263         /// <devdoc>
264         ///    <para>[To be supplied.]</para>
265         /// </devdoc>
266         public bool IsAsync {
267             get { return endMethodInfo != null; }
268         }
269
270         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.InParameters"]/*' />
271         /// <devdoc>
272         ///    <para>[To be supplied.]</para>
273         /// </devdoc>
274         public ParameterInfo[] InParameters {
275             get { return inParams; }
276         }
277
278         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.OutParameters"]/*' />
279         /// <devdoc>
280         ///    <para>[To be supplied.]</para>
281         /// </devdoc>
282         public ParameterInfo[] OutParameters {
283             get { return outParams; }
284         }
285
286         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.Parameters"]/*' />
287         /// <devdoc>
288         ///    <para>[To be supplied.]</para>
289         /// </devdoc>
290         public ParameterInfo[] Parameters {
291             get { return parameters; }
292         }
293
294         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.GetCustomAttributes"]/*' />
295         /// <devdoc>
296         ///    <para>[To be supplied.]</para>
297         /// </devdoc>
298         public object[] GetCustomAttributes(Type type) {
299             object[] attrForType = null;
300             attrForType = (object[])attributes[type];
301             if (attrForType != null)
302                 return attrForType;
303             lock (attributes) {
304                 attrForType = (object[])attributes[type];
305                 if (attrForType == null) {
306                     if (declaration != null) {
307                         object[] declAttributes = declaration.GetCustomAttributes(type, false);
308                         object[] implAttributes = methodInfo.GetCustomAttributes(type, false);
309                         if (implAttributes.Length > 0) {
310                             if (CanMerge(type)) {
311                                 ArrayList all = new ArrayList();
312                                 for (int i = 0; i < declAttributes.Length; i++) {
313                                     all.Add(declAttributes[i]);
314                                 }
315                                 for (int i = 0; i < implAttributes.Length; i++) {
316                                     all.Add(implAttributes[i]);
317                                 }
318                                 attrForType = (object[])all.ToArray(type);
319                             }
320                             else {
321                                 throw new InvalidOperationException(Res.GetString(Res.ContractOverride, methodInfo.Name, methodInfo.DeclaringType.FullName, declaration.DeclaringType.FullName, declaration.ToString(), implAttributes[0].ToString()));
322                             }
323                         }
324                         else {
325                             attrForType = declAttributes;
326                         }
327                     }
328                     else {
329                         attrForType = methodInfo.GetCustomAttributes(type, false);
330                     }
331                     attributes[type] = attrForType;
332                 }
333             }
334             return attrForType;
335         }
336
337
338         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.GetCustomAttribute"]/*' />
339         /// <devdoc>
340         ///    <para>[To be supplied.]</para>
341         /// </devdoc>
342         public object GetCustomAttribute(Type type) {
343             object[] attrs = GetCustomAttributes(type);
344             if (attrs.Length == 0) return null;
345             return attrs[0];
346         }
347
348         internal WebMethodAttribute MethodAttribute {
349             get {
350                 if (attribute == null) {
351                     attribute = (WebMethodAttribute)GetCustomAttribute(typeof(WebMethodAttribute));
352                     if (attribute == null) {
353                         attribute = new WebMethodAttribute();
354                     }
355                 }
356                 return attribute; 
357             } 
358         }
359
360         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.CustomAttributeProvider"]/*' />
361         /// <devdoc>
362         ///    <para>[To be supplied.]</para>
363         /// </devdoc>
364         public ICustomAttributeProvider CustomAttributeProvider {
365             // Custom attributes are always on the XXX (sync) or BeginXXX (async) method.
366             get { return methodInfo; }
367         }
368
369         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.ReturnTypeCustomAttributeProvider"]/*' />
370         /// <devdoc>
371         ///    <para>[To be supplied.]</para>
372         /// </devdoc>
373         public ICustomAttributeProvider ReturnTypeCustomAttributeProvider {
374             get {
375                 if (declaration != null)
376                     return declaration.ReturnTypeCustomAttributes;
377                 return methodInfo.ReturnTypeCustomAttributes; 
378             }
379         }
380
381         // Do not use this to property get custom attributes.  Instead use the CustomAttributeProvider 
382         // property which automatically handles where the custom attributes belong for async methods
383         // (which are actually two methods: BeginXXX and EndXXX).
384         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.MethodInfo"]/*' />
385         /// <devdoc>
386         ///    <para>[To be supplied.]</para>
387         /// </devdoc>
388         public MethodInfo MethodInfo {
389             get { return endMethodInfo == null ? methodInfo : null; }
390         }
391
392         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.BeginMethodInfo"]/*' />
393         /// <devdoc>
394         ///    <para>[To be supplied.]</para>
395         /// </devdoc>
396         public MethodInfo BeginMethodInfo {
397             get { return methodInfo; }
398         }
399
400         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.EndMethodInfo"]/*' />
401         /// <devdoc>
402         ///    <para>[To be supplied.]</para>
403         /// </devdoc>
404         public MethodInfo EndMethodInfo {
405             get { return endMethodInfo; }
406         }
407
408         static ParameterInfo[] GetInParameters(MethodInfo methodInfo, ParameterInfo[] paramInfos, int start, int length, bool mustBeIn) {
409             int count = 0;
410             for (int i = 0; i < length; i++) {
411                 ParameterInfo paramInfo = paramInfos[i + start];
412                 if (IsInParameter(paramInfo)) {
413                     count++;
414                 }
415                 else if (mustBeIn) {
416                     throw new InvalidOperationException(Res.GetString(Res.WebBadOutParameter, paramInfo.Name, methodInfo.DeclaringType.FullName,  paramInfo.Name));
417                 }
418             }
419
420             ParameterInfo[] ins = new ParameterInfo[count];
421             count = 0;
422             for (int i = 0; i < length; i++) {
423                 ParameterInfo paramInfo = paramInfos[i + start];
424                 if (IsInParameter(paramInfo)) {
425                     ins[count++] = paramInfo;
426                 }
427             }
428             return ins;
429         }
430
431         static ParameterInfo[] GetOutParameters(MethodInfo methodInfo, ParameterInfo[] paramInfos, int start, int length, bool mustBeOut) {
432             int count = 0;
433             for (int i = 0; i < length; i++) {
434                 ParameterInfo paramInfo = paramInfos[i + start];
435                 if (IsOutParameter(paramInfo)) {
436                     count++;
437                 }
438                 else if (mustBeOut) {
439                     throw new InvalidOperationException(Res.GetString(Res.WebInOutParameter, paramInfo.Name, methodInfo.DeclaringType.FullName,  paramInfo.Name));
440                 }
441             }
442
443             ParameterInfo[] outs = new ParameterInfo[count];
444             count = 0;
445             for (int i = 0; i < length; i++) {
446                 ParameterInfo paramInfo = paramInfos[i + start];
447                 if (IsOutParameter(paramInfo)) {
448                     outs[count++] = paramInfo;
449                 }
450             }
451             return outs;
452         }
453
454         static bool IsInParameter(ParameterInfo paramInfo) {
455             return !paramInfo.IsOut;
456         }
457
458         static bool IsOutParameter(ParameterInfo paramInfo) {
459             return paramInfo.IsOut || paramInfo.ParameterType.IsByRef;
460         }
461
462         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.IsBeginMethod"]/*' />
463         /// <devdoc>
464         ///    <para>[To be supplied.]</para>
465         /// </devdoc>
466         public static bool IsBeginMethod(MethodInfo methodInfo) {
467             return typeof(IAsyncResult).IsAssignableFrom(methodInfo.ReturnType) &&
468                 methodInfo.Name.StartsWith("Begin", StringComparison.Ordinal);
469         }
470
471         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.IsEndMethod"]/*' />
472         /// <devdoc>
473         ///    <para>[To be supplied.]</para>
474         /// </devdoc>
475         public static bool IsEndMethod(MethodInfo methodInfo) {
476             ParameterInfo[] paramInfos = methodInfo.GetParameters();
477             return paramInfos.Length > 0 && 
478                 typeof(IAsyncResult).IsAssignableFrom(paramInfos[0].ParameterType) &&
479                 methodInfo.Name.StartsWith("End", StringComparison.Ordinal);
480         }
481
482         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.Create"]/*' />
483         /// <devdoc>
484         ///    <para>[To be supplied.]</para>
485         /// </devdoc>
486         public static LogicalMethodInfo[] Create(MethodInfo[] methodInfos) {
487             return Create(methodInfos, LogicalMethodTypes.Async | LogicalMethodTypes.Sync, null);
488         }
489
490
491         /// <include file='doc\LogicalMethodInfo.uex' path='docs/doc[@for="LogicalMethodInfo.Create1"]/*' />
492         /// <devdoc>
493         ///    <para>[To be supplied.]</para>
494         /// </devdoc>
495         public static LogicalMethodInfo[] Create(MethodInfo[] methodInfos, LogicalMethodTypes types) {
496             return Create(methodInfos, types, null);
497         }
498
499         internal static LogicalMethodInfo[] Create(MethodInfo[] methodInfos, LogicalMethodTypes types, Hashtable declarations) {
500             ArrayList begins = (types & LogicalMethodTypes.Async) != 0 ? new ArrayList() : null;
501             Hashtable ends = (types & LogicalMethodTypes.Async) != 0 ? new Hashtable() : null;
502             ArrayList syncs = (types & LogicalMethodTypes.Sync) != 0 ? new ArrayList() : null;
503
504             for (int i = 0; i < methodInfos.Length; i++) {
505                 MethodInfo methodInfo = methodInfos[i];
506                 if (IsBeginMethod(methodInfo)) {
507                     if (begins != null) begins.Add(methodInfo);
508                 }
509                 else if (IsEndMethod(methodInfo)) {
510                     if (ends != null) ends.Add(methodInfo.Name, methodInfo);
511                 }
512                 else {
513                     if (syncs != null) syncs.Add(methodInfo);
514                 }
515             }
516
517             int beginsCount = begins == null ? 0 : begins.Count;
518             int syncsCount = syncs == null ? 0 : syncs.Count;
519             int count = syncsCount + beginsCount;
520             LogicalMethodInfo[] methods = new LogicalMethodInfo[count];
521             count = 0;
522             for (int i = 0; i < syncsCount; i++) {
523                 MethodInfo syncMethod = (MethodInfo)syncs[i];
524                 WebMethod webMethod = declarations == null ? null : (WebMethod)declarations[syncMethod];
525                 methods[count] = new LogicalMethodInfo(syncMethod, webMethod);
526                 methods[count].CheckContractOverride();
527                 count++;
528             }
529             for (int i = 0; i < beginsCount; i++) {
530                 MethodInfo beginMethodInfo = (MethodInfo)begins[i];
531                 string endName = "End" + beginMethodInfo.Name.Substring(5);
532                 MethodInfo endMethodInfo = (MethodInfo)ends[endName];
533                 if (endMethodInfo == null) {
534                     throw new InvalidOperationException(Res.GetString(Res.WebAsyncMissingEnd, beginMethodInfo.DeclaringType.FullName, beginMethodInfo.Name, endName));
535                 }
536                 WebMethod webMethod = declarations == null ? null : (WebMethod)declarations[beginMethodInfo];
537                 methods[count++] = new LogicalMethodInfo(beginMethodInfo, endMethodInfo, webMethod);
538             }
539
540             return methods;
541         }
542
543         internal static HashAlgorithm HashAlgorithm {
544             get {
545                 if (hash == null) {
546                     hash = SHA1.Create();
547                 }
548                 return hash;
549             }
550         }
551
552         internal string GetKey() {
553             if (methodInfo == null)
554                 return string.Empty;
555             string key = methodInfo.DeclaringType.FullName + ":" + methodInfo.ToString();
556             // for very long method signatures use a hash string instead of actual method signature.
557             if (key.Length > 1024) {
558                 byte[] bytes = HashAlgorithm.ComputeHash(Encoding.UTF8.GetBytes(key));
559                 key = Convert.ToBase64String(bytes);
560             }
561             return key;
562         }
563
564         internal void CheckContractOverride() {
565             if (declaration == null)
566                 return;
567             methodInfo.GetParameters();
568             ParameterInfo[] parameters = methodInfo.GetParameters();
569             foreach (ParameterInfo p in parameters) {
570                 object[] attrs = p.GetCustomAttributes(false);
571                 foreach (object o in attrs) {
572                     if (o.GetType().Namespace == "System.Xml.Serialization") {
573                         throw new InvalidOperationException(Res.GetString(Res.ContractOverride, methodInfo.Name, methodInfo.DeclaringType.FullName, declaration.DeclaringType.FullName, declaration.ToString(), o.ToString()));
574                     }
575                 }
576             }
577         }
578
579         internal static bool CanMerge(Type type) {
580             if (type == typeof(SoapHeaderAttribute))
581                 return true;
582             if (typeof(SoapExtensionAttribute).IsAssignableFrom(type))
583                 return true;
584             return false;
585         }
586     }
587 }