1 // Copyright (c) Microsoft Corporation. All rights reserved.
3 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
4 // WHETHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
5 // WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
6 // THE ENTIRE RISK OF USE OR RESULTS IN CONNECTION WITH THE USE OF THIS CODE
7 // AND INFORMATION REMAINS WITH THE USER.
10 /*********************************************************************
11 * NOTE: A copy of this file exists at: WF\Common\Shared
12 * The two files must be kept in sync. Any change made here must also
13 * be made to WF\Common\Shared\TypeSystemHelpers.cs
14 *********************************************************************/
15 namespace System.Workflow.Activities.Common
18 using System.Collections;
19 using System.Collections.Specialized;
20 using System.Collections.Generic;
21 using System.Globalization;
22 using System.Reflection;
24 using System.Text.RegularExpressions;
25 using System.Diagnostics.CodeAnalysis;
26 using System.Workflow.ComponentModel.Compiler;
28 internal static class ParseHelpers
30 private static readonly Version emptyVersion = new Version(0, 0, 0, 0);
31 private const string VersionTag = "version";
32 private const string CultureTag = "culture";
33 private const string PublicKeyTokenTag = "publickeytoken";
35 private static readonly ArrayList VBKeywords = new ArrayList(new string[] { "Integer", "String", "Boolean", "Object", "Void", "Single", "Double", "Char", "DateTime", "Long", "Byte", "Short", "Single", "Double", "Decimal", "UInteger", "ULong", "SByte", "UShort" });
36 private static readonly ArrayList CSKeywords = new ArrayList(new string[] { "int", "string", "bool", "object", "void", "float", "double", "char", "Date", "long", "byte", "short", "Single", "double", "decimal", "uint", "ulong", "sbyte", "ushort" });
37 private static readonly string[] DotNetKeywords = new string[] { "System.Int32", "System.String", "System.Boolean", "System.Object", "System.Void", "System.Single", "System.Double", "System.Char", "System.DateTime", "System.Int64", "System.Byte", "System.Int16", "System.Single", "System.Double", "System.Decimal", "System.UInt32", "System.UInt64", "System.SByte", "System.UInt16" };
39 internal enum ParseTypeNameLanguage
46 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
47 internal static bool ParseTypeName(string inputTypeName, ParseTypeNameLanguage parseTypeNameLanguage, out string typeName, out string[] parameters, out string elemantDecorator)
49 typeName = string.Empty;
51 elemantDecorator = string.Empty;
53 // replace all language specific array\generic chars with the net-framework's representation
54 if (parseTypeNameLanguage == ParseTypeNameLanguage.VB)
55 inputTypeName = inputTypeName.Replace('(', '[').Replace(')', ']');
56 else if (parseTypeNameLanguage == ParseTypeNameLanguage.CSharp)
57 inputTypeName = inputTypeName.Replace('<', '[').Replace('>', ']');
59 int endIndex = inputTypeName.LastIndexOfAny(new char[] { ']', '&', '*' });
63 typeName = inputTypeName;
65 else if (inputTypeName[endIndex] == ']') //array or generic
67 int startIndex = endIndex;
69 while ((startIndex > 0) && (nestLevel > 0))
72 if (inputTypeName[startIndex] == ']')
74 else if (inputTypeName[startIndex] == '[')
80 typeName = inputTypeName.Substring(0, startIndex) + inputTypeName.Substring(endIndex + 1);
82 string bracketContent = inputTypeName.Substring(startIndex + 1, endIndex - startIndex - 1).Trim();
83 if ((bracketContent == String.Empty) || (bracketContent.TrimStart()[0] == ','))
86 elemantDecorator = "[" + bracketContent + "]";
90 // Isolate the parameters (looking for commas alone will not cover cases
91 // when parameters are multi-dim array or generics...
93 char[] genericParamChars = bracketContent.ToCharArray();
94 for (int loop = 0; loop < genericParamChars.Length; loop++)
96 if (genericParamChars[loop] == '[')
98 else if (genericParamChars[loop] == ']')
100 else if ((genericParamChars[loop] == ',') && (nestingLevel == 0))
101 genericParamChars[loop] = '$';
103 // split to get the list of generic arguments
104 parameters = new string(genericParamChars).Split(new char[] { '$' });
106 // clean the parameters
107 for (int loop = 0; loop < parameters.Length; loop++)
109 parameters[loop] = parameters[loop].Trim();
111 // remove extra brackects if exist
112 if (parameters[loop][0] == '[')
113 parameters[loop] = parameters[loop].Substring(1, parameters[loop].Length - 2);
115 // remove the "Of " keyword form VB parameters
116 if ((parseTypeNameLanguage == ParseTypeNameLanguage.VB) && (parameters[loop].StartsWith("Of ", StringComparison.OrdinalIgnoreCase)))
117 parameters[loop] = parameters[loop].Substring(3).TrimStart();
121 else // byref, pointer
123 typeName = inputTypeName.Substring(0, endIndex) + inputTypeName.Substring(endIndex + 1);
124 elemantDecorator = inputTypeName.Substring(endIndex, 1);
127 //Work around: we need to account for these langugue keywords and provide the correct type for them.
128 // A tighter way to achieve this should be found.
129 if ((parseTypeNameLanguage == ParseTypeNameLanguage.CSharp) && CSKeywords.Contains(typeName))
130 typeName = DotNetKeywords[CSKeywords.IndexOf(typeName)];
131 else if ((parseTypeNameLanguage == ParseTypeNameLanguage.VB) && VBKeywords.Contains(typeName))
132 typeName = DotNetKeywords[VBKeywords.IndexOf(typeName)];
137 internal static bool AssemblyNameEquals(AssemblyName thisName, AssemblyName thatName)
139 // Simplest check -- the assembly name must match.
140 if (thisName.Name == null || thatName.Name == null)
143 if (!thatName.Name.Equals(thisName.Name))
146 // Next, version checks. We are comparing AGAINST thatName,
147 // so if thatName has a version defined, we must match.
148 Version thatVersion = thatName.Version;
149 if (thatVersion != null && thatVersion != emptyVersion && thatVersion != thisName.Version)
152 // Same story for culture
153 CultureInfo thatCulture = thatName.CultureInfo;
154 if (thatCulture != null && !thatCulture.Equals(CultureInfo.InvariantCulture))
156 CultureInfo thisCulture = thisName.CultureInfo;
157 if (thisCulture == null)
160 // the requested culture must either equal, or be a parent of
164 if (thatCulture.Equals(thisCulture))
166 thisCulture = thisCulture.Parent;
167 if (thisCulture.Equals(CultureInfo.InvariantCulture))
172 // And the same thing for the public token
173 byte[] thatToken = thatName.GetPublicKeyToken();
174 if (thatToken != null && thatToken.Length != 0)
176 byte[] thisToken = thisName.GetPublicKeyToken();
177 if (thisToken == null)
179 if (thatToken.Length != thisToken.Length)
181 for (int i = 0; i < thatToken.Length; i++)
183 if (thatToken[i] != thisToken[i])
190 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
191 internal static bool AssemblyNameEquals(AssemblyName thisName, string thatName)
193 if (thisName == null || string.IsNullOrEmpty(thisName.Name))
195 if (string.IsNullOrEmpty(thatName))
198 string[] parts = thatName.Split(',');
199 if (parts.Length == 0)
202 string thatAssemblyName = parts[0].Trim();
203 if (!thatAssemblyName.Equals(thisName.Name))
206 if (parts.Length == 1)
209 Version thatVersion = null;
210 CultureInfo thatCulture = null;
211 byte[] thatToken = null;
212 for (int index = 1; index < parts.Length; index++)
214 int indexOfEquals = parts[index].IndexOf('=');
215 if (indexOfEquals != -1)
217 string partName = parts[index].Substring(0, indexOfEquals).Trim().ToLowerInvariant();
218 string partValue = parts[index].Substring(indexOfEquals + 1).Trim().ToLowerInvariant();
219 if (string.IsNullOrEmpty(partValue))
224 case ParseHelpers.VersionTag:
225 thatVersion = new Version(partValue);
227 case ParseHelpers.CultureTag:
228 if (!string.Equals(partValue, "neutral", StringComparison.OrdinalIgnoreCase))
229 thatCulture = new CultureInfo(partValue);
231 case ParseHelpers.PublicKeyTokenTag:
232 if (!string.Equals(partValue, "null", StringComparison.OrdinalIgnoreCase))
234 thatToken = new byte[partValue.Length / 2];
235 for (int i = 0; i < thatToken.Length; i++)
236 thatToken[i] = Byte.Parse(partValue.Substring(i * 2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
245 if (thatVersion != null && thatVersion != emptyVersion && thatVersion != thisName.Version)
248 if (thatCulture != null && !thatCulture.Equals(CultureInfo.InvariantCulture))
250 CultureInfo thisCulture = thisName.CultureInfo;
251 if (thisCulture == null)
254 // the requested culture must either equal, or be a parent of
258 if (thatCulture.Equals(thisCulture))
260 thisCulture = thisCulture.Parent;
261 if (thisCulture.Equals(CultureInfo.InvariantCulture))
266 if (thatToken != null && thatToken.Length != 0)
268 byte[] thisToken = thisName.GetPublicKeyToken();
269 if (thisToken == null)
271 if (thatToken.Length != thisToken.Length)
273 for (int i = 0; i < thatToken.Length; i++)
275 if (thatToken[i] != thisToken[i])
283 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
284 internal static string FormatType(Type type, SupportedLanguages language)
286 string typeName = string.Empty;
289 typeName = FormatType(type.GetElementType(), language);
290 if (language == SupportedLanguages.CSharp)
295 typeName += new string(',', type.GetArrayRank() - 1);
296 if (language == SupportedLanguages.CSharp)
303 typeName = type.FullName;
304 int indexOfSpecialChar = typeName.IndexOf('`');
305 if (indexOfSpecialChar != -1)
306 typeName = typeName.Substring(0, indexOfSpecialChar);
307 typeName = typeName.Replace('+', '.');
309 if (type.ContainsGenericParameters || type.IsGenericType)
311 Type[] genericArguments = type.GetGenericArguments();
312 if (language == SupportedLanguages.CSharp)
318 foreach (Type genericArgument in genericArguments)
324 if (language == SupportedLanguages.VB)
328 typeName += FormatType(genericArgument, language);
331 if (language == SupportedLanguages.CSharp)
340 // Helper method to format a type name (language invariant) to a specific language
341 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
342 internal static string FormatType(string type, SupportedLanguages language)
344 string formattedType = string.Empty;
345 string[] genericParamTypeNames = null;
346 string baseTypeName = string.Empty;
347 string elementDecorators = string.Empty;
348 if (ParseHelpers.ParseTypeName(type, ParseHelpers.ParseTypeNameLanguage.NetFramework, out baseTypeName, out genericParamTypeNames, out elementDecorators))
350 if (elementDecorators.Length > 0)
352 // VB uses '()' for arrays
353 if (language == SupportedLanguages.VB)
354 elementDecorators = elementDecorators.Replace('[', '(').Replace(']', ')');
356 formattedType = FormatType(baseTypeName, language) + elementDecorators;
358 else if (genericParamTypeNames != null && genericParamTypeNames.Length > 0)
361 formattedType = FormatType(baseTypeName, language);
363 // add generic arguments
364 if (language == SupportedLanguages.CSharp)
365 formattedType += '<';
367 formattedType += '(';
370 foreach (string genericArgument in genericParamTypeNames)
373 formattedType += ", ";
376 if (language == SupportedLanguages.VB)
377 formattedType += "Of ";
381 formattedType += FormatType(genericArgument, language);
384 if (language == SupportedLanguages.CSharp)
385 formattedType += '>';
387 formattedType += ')';
391 // non generic, non decorated type - simple cleanup
392 formattedType = baseTypeName.Replace('+', '.');
394 int indexOfSpecialChar = formattedType.IndexOf('`');
395 if (indexOfSpecialChar != -1)
396 formattedType = formattedType.Substring(0, indexOfSpecialChar);
398 indexOfSpecialChar = formattedType.IndexOf(',');
399 if (indexOfSpecialChar != -1)
400 formattedType = formattedType.Substring(0, indexOfSpecialChar);
405 return formattedType;
408 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
409 internal static Type ParseTypeName(ITypeProvider typeProvider, SupportedLanguages language, string typeName)
411 Type returnType = null;
413 returnType = typeProvider.GetType(typeName, false);
414 if (returnType == null)
416 string simpleTypeName = String.Empty;
417 string decoratorString = String.Empty;
418 string[] parameters = null;
419 if (ParseTypeName(typeName, language == SupportedLanguages.CSharp ? ParseTypeNameLanguage.CSharp : ParseTypeNameLanguage.VB, out simpleTypeName, out parameters, out decoratorString))
421 returnType = typeProvider.GetType(simpleTypeName + decoratorString, false);