< Summary

Class:Towel.Meta
Assembly:Towel
File(s):File 1: /home/runner/work/Towel/Towel/Sources/Towel/Meta.cs
Covered lines:547
Uncovered lines:99
Coverable lines:646
Total lines:1213
Line coverage:84.6% (547 of 646)
Covered branches:218
Total branches:330
Branch coverage:66% (218 of 330)

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
File 1: GetTryParseMethod()100%1100%
File 1: GetTryParseMethod(...)83.33%6100%
File 1: .cctor()100%1100%
File 1: GetFactorialMethod()100%1100%
File 1: GetFactorialMethod(...)50%6100%
File 1: .cctor()100%1100%
File 1: GetIsPrimeMethod()100%1100%
File 1: GetIsPrimeMethod(...)50%6100%
File 1: .cctor()100%1100%
File 1: GetIsNonNegativeMethod()100%10%
File 1: GetIsNonNegativeMethod(...)0%60%
File 1: .cctor()100%10%
File 1: GetIsNegativeMethod()100%1100%
File 1: GetIsNegativeMethod(...)83.33%6100%
File 1: .cctor()100%1100%
File 1: GetIsPositiveMethod()100%1100%
File 1: GetIsPositiveMethod(...)50%6100%
File 1: .cctor()100%1100%
File 1: GetIsEvenMethod()100%1100%
File 1: GetIsEvenMethod(...)50%6100%
File 1: .cctor()100%1100%
File 1: GetIsOddMethod()100%1100%
File 1: GetIsOddMethod(...)50%6100%
File 1: .cctor()100%1100%
File 1: GetIsIntegerMethod()100%1100%
File 1: GetIsIntegerMethod(...)50%6100%
File 1: .cctor()100%1100%
File 1: GetLessThanMethod()100%10%
File 1: GetLessThanMethod(...)0%60%
File 1: .cctor()100%10%
File 1: GetGreaterThanMethod()100%10%
File 1: GetGreaterThanMethod(...)0%60%
File 1: .cctor()100%10%
File 1: HasImplicitCast()100%10%
File 1: HasExplicitCast()100%10%
File 1: HasImplicitCast(...)100%10%
File 1: HasExplicitCast(...)100%10%
File 1: HasCast(...)0%100%
File 1: .cctor()100%10%
File 1: ConvertToCSharpSource(...)100%1100%
File 1: GetEnumAttribute(...)100%1100%
File 1: GetEnumAttributes(...)100%1100%
File 1: GetLastEnumValue()50%271.42%
File 1: GetEventInfosWithAttribute()100%6100%
File 1: GetConstructorInfosWithAttribute()100%6100%
File 1: GetPropertyInfosWithAttribute()100%6100%
File 1: GetFieldInfosWithAttribute()100%6100%
File 1: GetMethodInfosWithAttribute()100%6100%
File 1: GetTypesWithAttribute()100%4100%
File 1: GetDerivedTypes(...)100%2100%
File 1: GetDirectoryPath(...)50%2100%
File 1: GetXmlName(...)50%4100%
File 1: GetXmlName(...)50%4100%
File 1: GetXmlName(...)50%4100%
File 1: GetXmlName(...)50%6100%
File 1: GetXmlName(...)50%6100%
File 1: GetXmlName(...)50%6100%
File 1: GetXmlNameMethodBase(...)88.23%3494.11%
File 1: GetXmlDocumenationFormattedString(...)84.61%2697.95%
File 1: GetXmlNameTypeSegment(...)100%1100%
File 1: .cctor()100%1100%
File 1: LoadXmlDocumentation(...)100%6100%
File 1: LoadXmlDocumentation(...)100%1100%
File 1: LoadXmlDocumentation(...)100%1100%
File 1: LoadXmlDocumentationNoLock(...)100%8100%
File 1: ClearXmlDocumentation()100%1100%
File 1: GetDocumentation(...)100%4100%
File 1: GetDocumentation(...)75%4100%
File 1: GetDocumentation(...)75%4100%
File 1: GetDocumentation(...)75%4100%
File 1: GetDocumentation(...)66.66%6100%
File 1: GetDocumentation(...)66.66%6100%
File 1: GetDocumentation(...)66.66%6100%
File 1: GetDocumentation(...)68.75%3295%
File 1: GetDocumentation(...)66.66%687.5%
File 1: IsLocalFunction(...)100%1100%

File(s)

/home/runner/work/Towel/Towel/Sources/Towel/Meta.cs

#LineLine coverage
 1using System.IO;
 2using System.Reflection;
 3using System.Text.RegularExpressions;
 4using System.Xml;
 5
 6namespace Towel;
 7
 8/// <summary>Constains static analysis methods of the code (reflection).</summary>
 9public static class Meta
 10{
 11  #region Getting Methods Via Reflection
 12
 13  #region System.Type.GetMethod
 14
 15#if false
 16    /// <summary>Gets a method on a type by signature.</summary>
 17    /// <typeparam name="Signature">
 18    /// The signature of the method to get as a delegate type. Must match the
 19    /// method in return type, parameter types, generic types, parameter names,
 20    /// generic parameter names, and delegate/method name.
 21    /// </typeparam>
 22    /// <param name="declaringType">The declaring type of the method to get.</param>
 23    /// <returns>The method info if found. null if not.</returns>
 24    public static MethodInfo GetMethod<Signature>(this Type declaringType)
 25      where Signature : Delegate
 26    {
 27      Type signature = typeof(Signature);
 28      string name = Regex.Replace(signature.Name, @"`\d+", string.Empty);
 29      Type[] signatureGenerics = signature.GetGenericArguments();
 30      MethodInfo signatureMethodInfo = signature.GetMethod("Invoke");
 31      ParameterInfo[] signatureParameters = signatureMethodInfo.GetParameters();
 32      Type signatureGeneric = signature.GetGenericTypeDefinition();
 33      Type[] signatureGenericGenerics = signatureGeneric.GetGenericArguments();
 34      foreach (MethodInfo currentMethodInfo in declaringType.GetMethods(
 35        BindingFlags.Instance |
 36        BindingFlags.Static |
 37        BindingFlags.Public |
 38        BindingFlags.NonPublic))
 39      {
 40        MethodInfo methodInfo = currentMethodInfo;
 41        if (methodInfo.Name != name ||
 42          signature.IsGenericType != methodInfo.IsGenericMethod)
 43        {
 44          continue;
 45        }
 46        if (signature.IsGenericType)
 47        {
 48          Type[] methodInfoGenerics = methodInfo.GetGenericArguments();
 49          if (methodInfoGenerics.Length != signatureGenerics.Length ||
 50            !Equate<Type>(signatureGenericGenerics, methodInfoGenerics, (a, b) => a.Name == b.Name))
 51          {
 52            continue;
 53          }
 54          try
 55          {
 56            methodInfo = methodInfo.MakeGenericMethod(signatureGenerics);
 57          }
 58          catch (ArgumentException)
 59          {
 60            // this is likely a contraint validation error
 61            continue;
 62          }
 63        }
 64        if (signatureMethodInfo.ReturnType != methodInfo.ReturnType ||
 65          !Equate<ParameterInfo>(signatureParameters, methodInfo.GetParameters(), (a, b) => a.ParameterType == b.Paramet
 66        {
 67          continue;
 68        }
 69        return methodInfo;
 70      }
 71      return null;
 72    }
 73#endif
 74
 75  #endregion
 76
 77  #region GetTryParseMethod
 78
 79  /// <summary>Gets the TryParse <see cref="MethodInfo"/> on a type if it exists [<see cref="bool"/> TryParse(<see cref=
 80  /// <typeparam name="T">The type of the out parameter.</typeparam>
 81  /// <returns>The TryParse <see cref="MethodInfo"/> if found or null if not.</returns>
 482  public static MethodInfo? GetTryParseMethod<T>() => GetTryParseMethodCache<T>.Value;
 83
 84  /// <summary>Gets the TryParse <see cref="MethodInfo"/> on a type if it exists [<see cref="bool"/> TryParse(<see cref=
 85  /// <param name="a">The type of the out parameter.</param>
 86  /// <returns>The TryParse <see cref="MethodInfo"/> if found or null if not.</returns>
 87  public static MethodInfo? GetTryParseMethod(Type a)
 2588  {
 2589    if (a is null) throw new ArgumentNullException(nameof(a));
 2590    MethodInfo? methodInfo = a.GetMethod("TryParse",
 2591      BindingFlags.Static |
 2592      BindingFlags.Public |
 2593      BindingFlags.NonPublic,
 2594      null,
 2595      Ɐ(typeof(string), a.MakeByRefType()),
 2596      null);
 2597    return methodInfo is not null && methodInfo.ReturnType == typeof(bool)
 2598      ? methodInfo
 2599      : null;
 25100  }
 101
 102  internal static class GetTryParseMethodCache<T>
 103  {
 4104    internal static readonly MethodInfo? Value = GetTryParseMethod(typeof(T));
 105  }
 106
 107  #endregion
 108
 109  #region GetFactorialMethod
 110
 111  /// <summary>Gets the Factorial <see cref="MethodInfo"/> on a type if it exists [<see cref="bool"/> Factorial(<typepar
 112  /// <typeparam name="T">The type of the out parameter.</typeparam>
 113  /// <returns>The IsPrime <see cref="MethodInfo"/> if found or null if not.</returns>
 4114  public static MethodInfo? GetFactorialMethod<T>() => GetFactorialMethodCache<T>.Value;
 115
 116  /// <summary>Gets the Factorial <see cref="MethodInfo"/> on a type if it exists [<see cref="bool"/> Factorial(<paramre
 117  /// <param name="a">The type of the out parameter.</param>
 118  /// <returns>The IsNonNegative <see cref="MethodInfo"/> if found or null if not.</returns>
 119  public static MethodInfo? GetFactorialMethod(Type a)
 4120  {
 4121    if (a is null) throw new ArgumentNullException(nameof(a));
 4122    MethodInfo? methodInfo = a.GetMethod("Factorial",
 4123      BindingFlags.Static |
 4124      BindingFlags.Public |
 4125      BindingFlags.NonPublic,
 4126      null,
 4127      Ɐ(a),
 4128      null);
 4129    return methodInfo is not null && methodInfo.ReturnType == typeof(bool)
 4130        ? methodInfo
 4131        : null;
 4132  }
 133
 134  internal static class GetFactorialMethodCache<T>
 135  {
 4136    internal static readonly MethodInfo? Value = GetFactorialMethod(typeof(T));
 137  }
 138
 139  #endregion
 140
 141  #region GetIsPrimeMethod
 142
 143  /// <summary>Gets the IsPrime <see cref="MethodInfo"/> on a type if it exists [<see cref="bool"/> IsPrime(<typeparamre
 144  /// <typeparam name="T">The type of the out parameter.</typeparam>
 145  /// <returns>The IsPrime <see cref="MethodInfo"/> if found or null if not.</returns>
 1146  public static MethodInfo? GetIsPrimeMethod<T>() => GetIsPrimeMethodCache<T>.Value;
 147
 148  /// <summary>Gets the IsPrime <see cref="MethodInfo"/> on a type if it exists [<see cref="bool"/> IsPrime(<paramref na
 149  /// <param name="a">The type of the out parameter.</param>
 150  /// <returns>The IsNonNegative <see cref="MethodInfo"/> if found or null if not.</returns>
 151  public static MethodInfo? GetIsPrimeMethod(Type a)
 1152  {
 1153    if (a is null) throw new ArgumentNullException(nameof(a));
 1154    MethodInfo? methodInfo = a.GetMethod("IsPrime",
 1155      BindingFlags.Static |
 1156      BindingFlags.Public |
 1157      BindingFlags.NonPublic,
 1158      null,
 1159      Ɐ(a),
 1160      null);
 1161    return methodInfo is not null && methodInfo.ReturnType == typeof(bool)
 1162      ? methodInfo
 1163      : null;
 1164  }
 165
 166  internal static class GetIsPrimeMethodCache<T>
 167  {
 1168    internal static readonly MethodInfo? Value = GetIsPrimeMethod(typeof(T));
 169  }
 170
 171  #endregion
 172
 173  #region GetIsNonNegativeMethod
 174
 175  /// <summary>Gets the IsNonNegative <see cref="MethodInfo"/> on a type if it exists [<see cref="bool"/> IsNonNegative(
 176  /// <typeparam name="T">The type of the out parameter.</typeparam>
 177  /// <returns>The IsNonNegative <see cref="MethodInfo"/> if found or null if not.</returns>
 0178  public static MethodInfo? GetIsNonNegativeMethod<T>() => GetIsNonNegativeMethodCache<T>.Value;
 179
 180  /// <summary>Gets the IsNonNegative <see cref="MethodInfo"/> on a type if it exists [<see cref="bool"/> IsNonNegative(
 181  /// <param name="a">The type of the out parameter.</param>
 182  /// <returns>The IsNonNegative <see cref="MethodInfo"/> if found or null if not.</returns>
 183  public static MethodInfo? GetIsNonNegativeMethod(Type a)
 0184  {
 0185    if (a is null) throw new ArgumentNullException(nameof(a));
 0186    MethodInfo? methodInfo = a.GetMethod("IsNonNegative",
 0187      BindingFlags.Static |
 0188      BindingFlags.Public |
 0189      BindingFlags.NonPublic,
 0190      null,
 0191      Ɐ(a),
 0192      null);
 0193    return methodInfo is not null && methodInfo.ReturnType == typeof(bool)
 0194      ? methodInfo
 0195      : null;
 0196  }
 197
 198  internal static class GetIsNonNegativeMethodCache<T>
 199  {
 0200    internal static readonly MethodInfo? Value = GetIsNonNegativeMethod(typeof(T));
 201  }
 202
 203  #endregion
 204
 205  #region GetIsNegativeMethod
 206
 207  /// <summary>Gets the IsNegative <see cref="MethodInfo"/> on a type if it exists [<see cref="bool"/> IsNegative(<typep
 208  /// <typeparam name="T">The type of the out parameter.</typeparam>
 209  /// <returns>The IsNegative <see cref="MethodInfo"/> if found or null if not.</returns>
 4210  public static MethodInfo? GetIsNegativeMethod<T>() => GetIsNegativeMethodCache<T>.Value;
 211
 212  /// <summary>Gets the IsNegative <see cref="MethodInfo"/> on a type if it exists [<see cref="bool"/> IsNegative(<param
 213  /// <param name="a">The type of the out parameter.</param>
 214  /// <returns>The IsNegative <see cref="MethodInfo"/> if found or null if not.</returns>
 215  public static MethodInfo? GetIsNegativeMethod(Type a)
 4216  {
 4217    if (a is null) throw new ArgumentNullException(nameof(a));
 4218    MethodInfo? methodInfo = a.GetMethod("IsNegative",
 4219      BindingFlags.Static |
 4220      BindingFlags.Public |
 4221      BindingFlags.NonPublic,
 4222      null,
 4223      Ɐ(a),
 4224      null);
 4225    return methodInfo is not null && methodInfo.ReturnType == typeof(bool)
 4226        ? methodInfo
 4227        : null;
 4228  }
 229
 230  internal static class GetIsNegativeMethodCache<T>
 231  {
 4232    internal static readonly MethodInfo? Value = GetIsNegativeMethod(typeof(T));
 233  }
 234
 235  #endregion
 236
 237  #region GetIsPositiveMethod
 238
 239  /// <summary>Gets the IsPositive <see cref="MethodInfo"/> on a type if it exists [<see cref="bool"/> IsPositive(<typep
 240  /// <typeparam name="T">The type of the out parameter.</typeparam>
 241  /// <returns>The IsPositive <see cref="MethodInfo"/> if found or null if not.</returns>
 4242  public static MethodInfo? GetIsPositiveMethod<T>() => GetIsPositiveMethodCache<T>.Value;
 243
 244  /// <summary>Gets the IsPositive <see cref="MethodInfo"/> on a type if it exists [<see cref="bool"/> IsPositive(<param
 245  /// <param name="a">The type of the out parameter.</param>
 246  /// <returns>The IsPositive <see cref="MethodInfo"/> if found or null if not.</returns>
 247  public static MethodInfo? GetIsPositiveMethod(Type a)
 4248  {
 4249    if (a is null) throw new ArgumentNullException(nameof(a));
 4250    MethodInfo? methodInfo = a.GetMethod("IsPositive",
 4251      BindingFlags.Static |
 4252      BindingFlags.Public |
 4253      BindingFlags.NonPublic,
 4254      null,
 4255      Ɐ(a),
 4256      null);
 4257    return methodInfo is not null && methodInfo.ReturnType == typeof(bool)
 4258        ? methodInfo
 4259        : null;
 4260  }
 261
 262  internal static class GetIsPositiveMethodCache<T>
 263  {
 4264    internal static readonly MethodInfo? Value = GetIsPositiveMethod(typeof(T));
 265  }
 266
 267  #endregion
 268
 269  #region GetIsEvenMethod
 270
 271  /// <summary>Gets the IsEven <see cref="MethodInfo"/> on a type if it exists [<see cref="bool"/> IsEven(<typeparamref 
 272  /// <typeparam name="T">The type of the out parameter.</typeparam>
 273  /// <returns>The IsEven <see cref="MethodInfo"/> if found or null if not.</returns>
 4274  public static MethodInfo? GetIsEvenMethod<T>() => GetIsEvenMethodCache<T>.Value;
 275
 276  /// <summary>Gets the IsEven <see cref="MethodInfo"/> on a type if it exists [<see cref="bool"/> IsEven(<paramref name
 277  /// <param name="a">The type of the out parameter.</param>
 278  /// <returns>The IsEven <see cref="MethodInfo"/> if found or null if not.</returns>
 279  public static MethodInfo? GetIsEvenMethod(Type a)
 4280  {
 4281    if (a is null) throw new ArgumentNullException(nameof(a));
 4282    MethodInfo? methodInfo = a.GetMethod(
 4283      "IsOdd",
 4284      BindingFlags.Static |
 4285      BindingFlags.Public |
 4286      BindingFlags.NonPublic,
 4287      null,
 4288      Ɐ(a),
 4289      null);
 4290    return methodInfo is not null && methodInfo.ReturnType == typeof(bool)
 4291        ? methodInfo
 4292        : null;
 4293  }
 294
 295  internal static class GetIsEvenMethodCache<T>
 296  {
 4297    internal static readonly MethodInfo? Value = GetIsEvenMethod(typeof(T));
 298  }
 299
 300  #endregion
 301
 302  #region GetIsOddMethod
 303
 304  /// <summary>Gets the IsOdd <see cref="MethodInfo"/> on a type if it exists [<see cref="bool"/> IsOdd(<typeparamref na
 305  /// <typeparam name="T">The type of the out parameter.</typeparam>
 306  /// <returns>The IsOdd <see cref="MethodInfo"/> if found or null if not.</returns>
 8307  public static MethodInfo? GetIsOddMethod<T>() => GetIsOddMethodCache<T>.Value;
 308
 309  /// <summary>Gets the IsOdd <see cref="MethodInfo"/> on a type if it exists [<see cref="bool"/> IsOdd(<paramref name="
 310  /// <param name="a">The type of the out parameter.</param>
 311  /// <returns>The IsOdd <see cref="MethodInfo"/> if found or null if not.</returns>
 312  public static MethodInfo? GetIsOddMethod(Type a)
 8313  {
 8314    if (a is null) throw new ArgumentNullException(nameof(a));
 8315    MethodInfo? methodInfo = a.GetMethod(
 8316      "IsOdd",
 8317      BindingFlags.Static |
 8318      BindingFlags.Public |
 8319      BindingFlags.NonPublic,
 8320      null,
 8321      Ɐ(a),
 8322      null);
 8323    return methodInfo is not null && methodInfo.ReturnType == typeof(bool)
 8324        ? methodInfo
 8325        : null;
 8326  }
 327
 328  internal static class GetIsOddMethodCache<T>
 329  {
 8330    internal static readonly MethodInfo? Value = GetIsOddMethod(typeof(T));
 331  }
 332
 333  #endregion
 334
 335  #region GetIsIntegerMethod
 336
 337  /// <summary>Gets the IsInteger <see cref="MethodInfo"/> on a type if it exists [<see cref="bool"/> IsInteger(<typepar
 338  /// <typeparam name="T">The type of the out parameter.</typeparam>
 339  /// <returns>The TryParse <see cref="MethodInfo"/> if found or null if not.</returns>
 4340  public static MethodInfo? GetIsIntegerMethod<T>() => GetIsIntegerMethodCache<T>.Value;
 341
 342  /// <summary>Gets the IsInteger <see cref="MethodInfo"/> on a type if it exists [<see cref="bool"/> IsInteger(<paramre
 343  /// <param name="a">The type of the out parameter.</param>
 344  /// <returns>The TryParse <see cref="MethodInfo"/> if found or null if not.</returns>
 345  public static MethodInfo? GetIsIntegerMethod(Type a)
 4346  {
 4347    if (a is null) throw new ArgumentNullException(nameof(a));
 4348    MethodInfo? methodInfo = a.GetMethod(
 4349      "IsInteger",
 4350      BindingFlags.Static |
 4351      BindingFlags.Public |
 4352      BindingFlags.NonPublic,
 4353      null,
 4354      Ɐ(a),
 4355      null);
 4356    return methodInfo is not null && methodInfo.ReturnType == typeof(bool)
 4357        ? methodInfo
 4358        : null;
 4359  }
 360
 361  internal static class GetIsIntegerMethodCache<T>
 362  {
 4363    internal static readonly MethodInfo? Value = GetIsIntegerMethod(typeof(T));
 364  }
 365
 366  #endregion
 367
 368  #region GetLessThanMethod
 369
 370  /// <summary>Determines if an op_LessThan member exists.</summary>
 371  /// <typeparam name="TA">The type of the left operand.</typeparam>
 372  /// <typeparam name="TB">The type of the right operand.</typeparam>
 373  /// <typeparam name="TC">The type of the return.</typeparam>
 374  /// <returns>True if the op_LessThan member exists or false if not.</returns>
 0375  public static MethodInfo? GetLessThanMethod<TA, TB, TC>() => GetLessThanMethodCache<TA, TB, TC>.Value;
 376
 377  /// <summary>Determines if an op_LessThan member exists.</summary>
 378  /// <param name="a">The type of the left operand.</param>
 379  /// <param name="b">The type of the right operand.</param>
 380  /// <param name="c">The type of the return.</param>
 381  /// <returns>True if the op_LessThan member exists or false if not.</returns>
 382  internal static MethodInfo? GetLessThanMethod(Type a, Type b, Type c)
 0383  {
 0384    if (a is null) throw new ArgumentNullException(nameof(a));
 0385    if (b is null) throw new ArgumentNullException(nameof(b));
 386    MethodInfo? CheckType(Type type)
 0387    {
 0388      MethodInfo? methodInfo = type.GetMethod(
 0389        "op_LessThan",
 0390        BindingFlags.Static |
 0391        BindingFlags.Public |
 0392        BindingFlags.NonPublic,
 0393        null,
 0394        Ɐ(a, b),
 0395        null);
 0396      return methodInfo is not null
 0397        && methodInfo.ReturnType == c
 0398        && methodInfo.IsSpecialName
 0399          ? methodInfo
 0400          : null;
 0401    }
 0402    return CheckType(a) ?? CheckType(b);
 0403  }
 404
 405  internal static class GetLessThanMethodCache<TA, TB, TC>
 406  {
 0407    internal static readonly MethodInfo? Value = GetLessThanMethod(typeof(TA), typeof(TB), typeof(TC));
 408  }
 409
 410  #endregion
 411
 412  #region GetGreaterThanMethod
 413
 414  /// <summary>Determines if an op_GreaterThan member exists.</summary>
 415  /// <typeparam name="TA">The type of the left operand.</typeparam>
 416  /// <typeparam name="TB">The type of the right operand.</typeparam>
 417  /// <typeparam name="TC">The type of the return.</typeparam>
 418  /// <returns>True if the op_GreaterThan member exists or false if not.</returns>
 0419  public static MethodInfo? GetGreaterThanMethod<TA, TB, TC>() => GetGreaterThanMethodCache<TA, TB, TC>.Value;
 420
 421  /// <summary>Determines if an op_GreaterThan member exists.</summary>
 422  /// <param name="a">The type of the left operand.</param>
 423  /// <param name="b">The type of the right operand.</param>
 424  /// <param name="c">The type of the return.</param>
 425  /// <returns>True if the op_GreaterThan member exists or false if not.</returns>
 426  internal static MethodInfo? GetGreaterThanMethod(Type a, Type b, Type c)
 0427  {
 0428    if (a is null) throw new ArgumentNullException(nameof(a));
 0429    if (b is null) throw new ArgumentNullException(nameof(b));
 430    MethodInfo? CheckType(Type type)
 0431    {
 0432      MethodInfo? methodInfo = type.GetMethod(
 0433        "op_GreaterThan",
 0434        BindingFlags.Static |
 0435        BindingFlags.Public |
 0436        BindingFlags.NonPublic,
 0437        null,
 0438        Ɐ(a, b),
 0439        null);
 0440      return methodInfo is not null
 0441        && methodInfo.ReturnType == c
 0442        && methodInfo.IsSpecialName
 0443          ? methodInfo
 0444          : null;
 0445    }
 0446    return CheckType(a) ?? CheckType(b);
 0447  }
 448
 449  internal static class GetGreaterThanMethodCache<TA, TB, TC>
 450  {
 0451    internal static readonly MethodInfo? Value = GetGreaterThanMethod(typeof(TA), typeof(TB), typeof(TC));
 452  }
 453
 454  #endregion
 455
 456  #endregion
 457
 458  #region Has[Implicit|Explicit]Cast
 459
 460  /// <summary>Determines if an implicit casting operator exists from one type to another.</summary>
 461  /// <typeparam name="TFrom">The parameter type of the implicit casting operator.</typeparam>
 462  /// <typeparam name="TTo">The return type fo the implicit casting operator.</typeparam>
 463  /// <returns>True if the implicit casting operator exists or false if not.</returns>
 0464  public static bool HasImplicitCast<TFrom, TTo>() => HasCastCache<TFrom, TTo>.Implicit;
 465
 466  /// <summary>Determines if an implicit casting operator exists from one type to another.</summary>
 467  /// <typeparam name="TFrom">The parameter type of the implicit casting operator.</typeparam>
 468  /// <typeparam name="TTo">The return type fo the implicit casting operator.</typeparam>
 469  /// <returns>True if the implicit casting operator exists or false if not.</returns>
 0470  public static bool HasExplicitCast<TFrom, TTo>() => HasCastCache<TFrom, TTo>.Implicit;
 471
 472  /// <summary>Determines if an implicit casting operator exists from one type to another.</summary>
 473  /// <param name="fromType">The parameter type of the implicit casting operator.</param>
 474  /// <param name="toType">The return type fo the implicit casting operator.</param>
 475  /// <returns>True if the implicit casting operator exists or false if not.</returns>
 0476  public static bool HasImplicitCast(Type fromType, Type toType) => HasCast(fromType, toType, true);
 477
 478  /// <summary>Determines if an implicit casting operator exists from one type to another.</summary>
 479  /// <param name="fromType">The parameter type of the implicit casting operator.</param>
 480  /// <param name="toType">The return type fo the implicit casting operator.</param>
 481  /// <returns>True if the implicit casting operator exists or false if not.</returns>
 0482  public static bool HasExplicitCast(Type fromType, Type toType) => HasCast(fromType, toType, false);
 483
 484  internal static bool HasCast(Type fromType, Type toType, bool @implicit)
 0485  {
 0486    if (fromType is null) throw new ArgumentNullException(nameof(fromType));
 0487    if (toType is null) throw new ArgumentNullException(nameof(toType));
 0488    string methodName = @implicit
 0489      ? "op_Implicit"
 0490      : "op_Explicit";
 491    bool CheckType(Type type)
 0492    {
 0493      MethodInfo? methodInfo = type.GetMethod(
 0494        methodName,
 0495        BindingFlags.Static |
 0496        BindingFlags.Public |
 0497        BindingFlags.NonPublic,
 0498        null,
 0499        Ɐ(fromType),
 0500        null);
 0501      return methodInfo is not null
 0502        && methodInfo.ReturnType == toType
 0503        && methodInfo.IsSpecialName;
 0504    }
 0505    if (CheckType(fromType) || CheckType(toType))
 0506    {
 0507      return true;
 508    }
 0509    return false;
 0510  }
 511
 512  internal static class HasCastCache<TFrom, TTo>
 513  {
 0514    internal static readonly bool Implicit = HasCast(typeof(TFrom), typeof(TTo), true);
 0515    internal static readonly bool Explicit = HasCast(typeof(TFrom), typeof(TTo), false);
 516  }
 517
 518  #endregion
 519
 520  #region System.Type.ConvertToCSharpSource
 521
 522  /// <summary>Converts a <see cref="System.Type"/> into a <see cref="string"/> as it would appear in C# source code.</s
 523  /// <param name="type">The <see cref="System.Type"/> to convert to a <see cref="string"/>.</param>
 524  /// <param name="showGenericParameters">If the generic parameters are the generic types, whether they should be shown 
 525  /// <returns>The <see cref="string"/> as the <see cref="System.Type"/> would appear in C# source code.</returns>
 526  public static string ConvertToCSharpSource(this Type type, bool showGenericParameters = false)
 77527  {
 77528    IQueue<Type> genericParameters = new QueueArray<Type>();
 135529    type.GetGenericArguments().Stepper(x => genericParameters.Enqueue(x));
 77530    return ConvertToCsharpSource(type);
 531
 532    string ConvertToCsharpSource(Type type)
 90533    {
 90534      if (type is null) throw new ArgumentNullException(nameof(type));
 90535      string result = type.IsNested
 90536        ? ConvertToCsharpSource(sourceof(type.DeclaringType, out string c1) ?? throw new ArgumentException(c1)) + "."
 90537        : type.Namespace + ".";
 90538      result += Regex.Replace(type.Name, "`.*", string.Empty);
 90539      if (type.IsGenericType)
 30540      {
 30541        result += "<";
 30542        bool firstIteration = true;
 210543        foreach (Type generic in type.GetGenericArguments())
 62544        {
 62545          if (genericParameters.Count <= 0)
 4546          {
 4547            break;
 548          }
 58549          Type correctGeneric = genericParameters.Dequeue();
 58550          result += (firstIteration ? string.Empty : ",") +
 58551            (correctGeneric.IsGenericParameter
 58552              ? (showGenericParameters ? (firstIteration ? string.Empty : " ") + correctGeneric.Name : string.Empty)
 58553              : (firstIteration ? string.Empty : " ") + ConvertToCSharpSource(correctGeneric, showGenericParameters));
 58554          firstIteration = false;
 58555        }
 30556        result += ">";
 30557      }
 90558      return result;
 90559    }
 77560  }
 561
 562  #endregion
 563
 564  #region System.Enum
 565
 566  /// <summary>Gets a custom attribute on an enum value by generic type.</summary>
 567  /// <typeparam name="TAttribute">The type of attribute to get.</typeparam>
 568  /// <param name="enum">The enum value to get the attribute of.</param>
 569  /// <returns>The attribute on the enum value of the provided type.</returns>
 570  public static TAttribute? GetEnumAttribute<TAttribute>(this Enum @enum)
 571    where TAttribute : Attribute
 296572  {
 296573    Type type = @enum.GetType();
 296574    MemberInfo memberInfo = type.GetMember(@enum.ToString())[0];
 296575    return memberInfo.GetCustomAttribute<TAttribute>();
 296576  }
 577
 578  /// <summary>Gets custom attributes on an enum value by generic type.</summary>
 579  /// <typeparam name="TAttribute">The type of attribute to get.</typeparam>
 580  /// <param name="enum">The enum value to get the attribute of.</param>
 581  /// <returns>The attributes on the enum value of the provided type.</returns>
 582  public static System.Collections.Generic.IEnumerable<TAttribute> GetEnumAttributes<TAttribute>(this Enum @enum)
 583    where TAttribute : Attribute
 122584  {
 122585    Type type = @enum.GetType();
 122586    MemberInfo memberInfo = type.GetMember(@enum.ToString())[0];
 122587    return memberInfo.GetCustomAttributes<TAttribute>();
 122588  }
 589
 590  /// <summary>Gets the maximum value of an enum.</summary>
 591  /// <typeparam name="TEnum">The enum type to get the maximum value of.</typeparam>
 592  /// <returns>The maximum enum value of the provided type.</returns>
 593  public static TEnum GetLastEnumValue<TEnum>()
 594    where TEnum : struct, Enum
 7595  {
 7596    TEnum[] values = (TEnum[])Enum.GetValues(typeof(TEnum));
 7597    if (values.Length is 0)
 0598    {
 0599      throw new InvalidOperationException("Attempting to get the last enum value of an enum type with no values.");
 600    }
 7601    return values[^1];
 7602  }
 603
 604  #endregion
 605
 606  #region System.Reflection.Assembly
 607
 608  /// <summary>Enumerates through all the events with a custom attribute.</summary>
 609  /// <typeparam name="TAttribute">The type of the custom attribute.</typeparam>
 610  /// <param name="assembly">The assembly to iterate through the events of.</param>
 611  /// <returns>The IEnumerable of the events with the provided attribute type.</returns>
 612  public static System.Collections.Generic.IEnumerable<EventInfo> GetEventInfosWithAttribute<TAttribute>(this Assembly a
 613    where TAttribute : Attribute
 1614  {
 693615    foreach (Type type in assembly.GetTypes())
 345616    {
 1057617      foreach (EventInfo eventInfo in type.GetEvents(
 345618        BindingFlags.Instance |
 345619        BindingFlags.Static |
 345620        BindingFlags.Public |
 345621        BindingFlags.NonPublic))
 11622      {
 11623        if (eventInfo.GetCustomAttributes(typeof(TAttribute), true).Length > 0)
 9624        {
 9625          yield return eventInfo;
 9626        }
 11627      }
 345628    }
 1629  }
 630
 631  /// <summary>Enumerates through all the constructors with a custom attribute.</summary>
 632  /// <typeparam name="TAttribute">The type of the custom attribute.</typeparam>
 633  /// <param name="assembly">The assembly to iterate through the constructors of.</param>
 634  /// <returns>The IEnumerable of the constructors with the provided attribute type.</returns>
 635  public static System.Collections.Generic.IEnumerable<ConstructorInfo> GetConstructorInfosWithAttribute<TAttribute>(thi
 636    where TAttribute : Attribute
 1637  {
 693638    foreach (Type type in assembly.GetTypes())
 345639    {
 1683640      foreach (ConstructorInfo constructorInfo in type.GetConstructors(
 345641        BindingFlags.Instance |
 345642        BindingFlags.Public |
 345643        BindingFlags.NonPublic))
 324644      {
 324645        if (constructorInfo.GetCustomAttributes(typeof(TAttribute), true).Length > 0)
 14646        {
 14647          yield return constructorInfo;
 14648        }
 324649      }
 345650    }
 1651  }
 652
 653  /// <summary>Enumerates through all the properties with a custom attribute.</summary>
 654  /// <typeparam name="TAttribute">The type of the custom attribute.</typeparam>
 655  /// <param name="assembly">The assembly to iterate through the properties of.</param>
 656  /// <returns>The IEnumerable of the properties with the provided attribute type.</returns>
 657  public static System.Collections.Generic.IEnumerable<PropertyInfo> GetPropertyInfosWithAttribute<TAttribute>(this Asse
 658    where TAttribute : Attribute
 1659  {
 693660    foreach (Type type in assembly.GetTypes())
 345661    {
 1131662      foreach (PropertyInfo propertyInfo in type.GetProperties(
 345663        BindingFlags.Instance |
 345664        BindingFlags.Static |
 345665        BindingFlags.Public |
 345666        BindingFlags.NonPublic))
 48667      {
 48668        if (propertyInfo.GetCustomAttributes(typeof(TAttribute), true).Length > 0)
 18669        {
 18670          yield return propertyInfo;
 18671        }
 48672      }
 345673    }
 1674  }
 675
 676  /// <summary>Enumerates through all the fields with a custom attribute.</summary>
 677  /// <typeparam name="TAttribute">The type of the custom attribute.</typeparam>
 678  /// <param name="assembly">The assembly to iterate through the fields of.</param>
 679  /// <returns>The IEnumerable of the fields with the provided attribute type.</returns>
 680  public static System.Collections.Generic.IEnumerable<FieldInfo> GetFieldInfosWithAttribute<TAttribute>(this Assembly a
 681    where TAttribute : Attribute
 1682  {
 693683    foreach (Type type in assembly.GetTypes())
 345684    {
 3095685      foreach (FieldInfo fieldInfo in type.GetFields(
 345686        BindingFlags.Instance |
 345687        BindingFlags.Static |
 345688        BindingFlags.Public |
 345689        BindingFlags.NonPublic))
 1030690      {
 1030691        if (fieldInfo.GetCustomAttributes(typeof(TAttribute), true).Length > 0)
 19692        {
 19693          yield return fieldInfo;
 19694        }
 1030695      }
 345696    }
 1697  }
 698
 699  /// <summary>Enumerates through all the methods with a custom attribute.</summary>
 700  /// <typeparam name="TAttribute">The type of the custom attribute.</typeparam>
 701  /// <param name="assembly">The assembly to iterate through the methods of.</param>
 702  /// <returns>The IEnumerable of the methods with the provided attribute type.</returns>
 703  public static System.Collections.Generic.IEnumerable<MethodInfo> GetMethodInfosWithAttribute<TAttribute>(this Assembly
 704    where TAttribute : Attribute
 25705  {
 17325706    foreach (Type type in assembly.GetTypes())
 8625707    {
 201775708      foreach (MethodInfo methodInfo in type.GetMethods(
 8625709        BindingFlags.Instance |
 8625710        BindingFlags.Static |
 8625711        BindingFlags.Public |
 8625712        BindingFlags.NonPublic))
 87950713      {
 87950714        if (methodInfo.GetCustomAttributes(typeof(TAttribute), true).Length > 0)
 183715        {
 183716          yield return methodInfo;
 183717        }
 87950718      }
 8625719    }
 25720  }
 721
 722  /// <summary>Enumerates through all the types with a custom attribute.</summary>
 723  /// <typeparam name="TAttribute">The type of the custom attribute.</typeparam>
 724  /// <param name="assembly">The assembly to iterate through the types of.</param>
 725  /// <returns>The IEnumerable of the types with the provided attribute type.</returns>
 726  public static System.Collections.Generic.IEnumerable<Type> GetTypesWithAttribute<TAttribute>(this Assembly assembly)
 727    where TAttribute : Attribute
 1728  {
 693729    foreach (Type type in assembly.GetTypes())
 345730    {
 345731      if (type.GetCustomAttributes(typeof(TAttribute), true).Length > 0)
 20732      {
 20733        yield return type;
 20734      }
 345735    }
 1736  }
 737
 738  /// <summary>Gets all the types in an assembly that derive from a base.</summary>
 739  /// <typeparam name="TBase">The base type to get the deriving types of.</typeparam>
 740  /// <param name="assembly">The assmebly to perform the search on.</param>
 741  /// <returns>The IEnumerable of the types that derive from the provided base.</returns>
 742  public static System.Collections.Generic.IEnumerable<Type> GetDerivedTypes<TBase>(this Assembly assembly)
 5743  {
 5744    Type @base = typeof(TBase);
 5745    return assembly.GetTypes().Where(type =>
 4880746      type != @base &&
 4880747      @base.IsAssignableFrom(type));
 5748  }
 749
 750  /// <summary>Gets the file path of an assembly.</summary>
 751  /// <param name="assembly">The assembly to get the file path of.</param>
 752  /// <returns>The file path of the assembly.</returns>
 753  public static string? GetDirectoryPath(this Assembly assembly)
 8754  {
 8755    string? directoryPath = Path.GetDirectoryName(assembly.Location);
 8756    return directoryPath == string.Empty ? null : directoryPath;
 8757  }
 758
 759  #endregion
 760
 761  #region GetXmlName
 762
 763  /// <summary>Gets the XML name of an <see cref="Type"/> as it appears in the XML docs.</summary>
 764  /// <param name="type">The field to get the XML name of.</param>
 765  /// <returns>The XML name of <paramref name="type"/> as it appears in the XML docs.</returns>
 766  public static string GetXmlName(this Type type)
 40767  {
 40768    if (type is null) throw new ArgumentNullException(nameof(type));
 40769    if (sourceof(type.FullName is null, out string c1)) throw new ArgumentException(c1, nameof(type));
 40770    LoadXmlDocumentation(type.Assembly);
 40771    return "T:" + GetXmlNameTypeSegment(type.FullName!);
 40772  }
 773
 774  /// <summary>Gets the XML name of an <see cref="MethodInfo"/> as it appears in the XML docs.</summary>
 775  /// <param name="methodInfo">The field to get the XML name of.</param>
 776  /// <returns>The XML name of <paramref name="methodInfo"/> as it appears in the XML docs.</returns>
 777  public static string GetXmlName(this MethodInfo methodInfo)
 107778  {
 107779    if (methodInfo is null) throw new ArgumentNullException(nameof(methodInfo));
 107780    if (sourceof(methodInfo.DeclaringType is null, out string c1)) throw new ArgumentException(c1, nameof(methodInfo));
 107781    return GetXmlNameMethodBase(methodInfo: methodInfo);
 107782  }
 783
 784  /// <summary>Gets the XML name of an <see cref="ConstructorInfo"/> as it appears in the XML docs.</summary>
 785  /// <param name="constructorInfo">The field to get the XML name of.</param>
 786  /// <returns>The XML name of <paramref name="constructorInfo"/> as it appears in the XML docs.</returns>
 787  public static string GetXmlName(this ConstructorInfo constructorInfo)
 29788  {
 29789    if (constructorInfo is null) throw new ArgumentNullException(nameof(constructorInfo));
 29790    if (sourceof(constructorInfo.DeclaringType is null, out string c1)) throw new ArgumentException(c1, nameof(construct
 29791    return GetXmlNameMethodBase(constructorInfo: constructorInfo);
 29792  }
 793
 794  /// <summary>Gets the XML name of an <see cref="PropertyInfo"/> as it appears in the XML docs.</summary>
 795  /// <param name="propertyInfo">The field to get the XML name of.</param>
 796  /// <returns>The XML name of <paramref name="propertyInfo"/> as it appears in the XML docs.</returns>
 797  public static string GetXmlName(this PropertyInfo propertyInfo)
 40798  {
 40799    if (propertyInfo is null) throw new ArgumentNullException(nameof(propertyInfo));
 40800    if (sourceof(propertyInfo.DeclaringType is null, out string c1)) throw new ArgumentException(c1, nameof(propertyInfo
 40801    if (sourceof(propertyInfo.DeclaringType!.FullName is null, out string c2)) throw new ArgumentException(c2, nameof(pr
 40802    return "P:" + GetXmlNameTypeSegment(propertyInfo.DeclaringType.FullName!) + "." + propertyInfo.Name;
 40803  }
 804
 805  /// <summary>Gets the XML name of an <see cref="FieldInfo"/> as it appears in the XML docs.</summary>
 806  /// <param name="fieldInfo">The field to get the XML name of.</param>
 807  /// <returns>The XML name of <paramref name="fieldInfo"/> as it appears in the XML docs.</returns>
 808  public static string GetXmlName(this FieldInfo fieldInfo)
 42809  {
 42810    if (fieldInfo is null) throw new ArgumentNullException(nameof(fieldInfo));
 42811    if (sourceof(fieldInfo.DeclaringType is null, out string c1)) throw new ArgumentException(c1, nameof(fieldInfo));
 42812    if (sourceof(fieldInfo.DeclaringType!.FullName is null, out string c2)) throw new ArgumentException(c2, nameof(field
 42813    return "F:" + GetXmlNameTypeSegment(fieldInfo.DeclaringType.FullName!) + "." + fieldInfo.Name;
 42814  }
 815
 816  /// <summary>Gets the XML name of an <see cref="EventInfo"/> as it appears in the XML docs.</summary>
 817  /// <param name="eventInfo">The event to get the XML name of.</param>
 818  /// <returns>The XML name of <paramref name="eventInfo"/> as it appears in the XML docs.</returns>
 819  public static string GetXmlName(this EventInfo eventInfo)
 18820  {
 18821    if (eventInfo is null) throw new ArgumentNullException(nameof(eventInfo));
 18822    if (sourceof(eventInfo.DeclaringType is null, out string c1)) throw new ArgumentException(c1, nameof(eventInfo));
 18823    if (sourceof(eventInfo.DeclaringType!.FullName is null, out string c2)) throw new ArgumentException(c2, nameof(event
 18824    return "E:" + GetXmlNameTypeSegment(eventInfo.DeclaringType.FullName!) + "." + eventInfo.Name;
 18825  }
 826
 827  internal static string GetXmlNameMethodBase(MethodInfo? methodInfo = null, ConstructorInfo? constructorInfo = null)
 136828  {
 136829    if (methodInfo is not null && constructorInfo is not null)
 0830    {
 0831      throw new TowelBugException($"{nameof(GetDocumentation)} {nameof(methodInfo)} is not null && {nameof(constructorIn
 832    }
 833
 136834    if (methodInfo is not null)
 107835    {
 107836      if (methodInfo.DeclaringType is null)
 0837      {
 0838        throw new ArgumentException($"{nameof(methodInfo)}.{nameof(Type.DeclaringType)} is null");
 839      }
 107840      else if (methodInfo.DeclaringType.IsGenericType)
 40841      {
 40842        methodInfo = methodInfo.DeclaringType.GetGenericTypeDefinition().GetMethods(
 40843          BindingFlags.Static |
 40844          BindingFlags.Public |
 40845          BindingFlags.Instance |
 156846          BindingFlags.NonPublic).First(x => x.MetadataToken == methodInfo.MetadataToken);
 40847      }
 107848    }
 849
 136850    MethodBase? methodBase = methodInfo ?? (MethodBase?)constructorInfo;
 136851    if (sourceof(methodBase is null, out string c1)) throw new TowelBugException(c1);
 136852    if (sourceof(methodBase!.DeclaringType is null, out string c2)) throw new ArgumentException(c2);
 853
 136854    LoadXmlDocumentation(methodBase.DeclaringType!.Assembly);
 855
 136856    MapHashLinked<int, string, StringEquate, StringHash> typeGenericMap = new();
 136857    Type[] typeGenericArguments = methodBase.DeclaringType.GetGenericArguments();
 474858    for (int i = 0; i < typeGenericArguments.Length; i++)
 101859    {
 101860      Type typeGeneric = typeGenericArguments[i];
 101861      typeGenericMap[typeGeneric.Name] = i;
 101862    }
 863
 136864    MapHashLinked<int, string, StringEquate, StringHash> methodGenericMap = new();
 136865    if (constructorInfo is null)
 107866    {
 107867      Type[] methodGenericArguments = methodBase.GetGenericArguments();
 310868      for (int i = 0; i < methodGenericArguments.Length; i++)
 48869      {
 48870        Type methodGeneric = methodGenericArguments[i];
 48871        methodGenericMap[methodGeneric.Name] = i;
 48872      }
 107873    }
 874
 136875    ParameterInfo[] parameterInfos = methodBase.GetParameters();
 876
 136877    string memberTypePrefix = "M:";
 136878    string declarationTypeString = GetXmlDocumenationFormattedString(methodBase.DeclaringType, false, typeGenericMap, me
 136879    string memberNameString =
 136880      constructorInfo is not null ? "#ctor" :
 136881      methodBase.Name;
 136882    string methodGenericArgumentsString =
 136883      methodGenericMap.Count > 0 ?
 136884      "``" + methodGenericMap.Count :
 136885      string.Empty;
 136886    string parametersString =
 136887      parameterInfos.Length > 0 ?
 196888      "(" + string.Join(",", methodBase.GetParameters().Select(x => GetXmlDocumenationFormattedString(x.ParameterType, t
 136889      string.Empty;
 890
 136891    string key =
 136892      memberTypePrefix +
 136893      declarationTypeString +
 136894      "." +
 136895      memberNameString +
 136896      methodGenericArgumentsString +
 136897      parametersString;
 898
 136899    if (methodInfo is not null &&
 136900      (methodBase.Name is "op_Implicit" ||
 136901      methodBase.Name is "op_Explicit"))
 16902    {
 16903      key += "~" + GetXmlDocumenationFormattedString(methodInfo.ReturnType, true, typeGenericMap, methodGenericMap);
 16904    }
 136905    return key;
 136906  }
 907
 908  internal static string GetXmlDocumenationFormattedString(
 909    Type type,
 910    bool isMethodParameter,
 911    MapHashLinked<int, string, StringEquate, StringHash> typeGenericMap,
 912    MapHashLinked<int, string, StringEquate, StringHash> methodGenericMap)
 537913  {
 537914    if (type.IsGenericParameter)
 138915    {
 138916      var (success, exception, methodIndex) = methodGenericMap.TryGet(type.Name);
 138917      return success
 138918        ? "``" + methodIndex
 138919        : "`" + typeGenericMap[type.Name];
 920    }
 399921    else if (type.HasElementType)
 72922    {
 72923      string elementTypeString = GetXmlDocumenationFormattedString(
 72924        type.GetElementType() ?? throw new ArgumentException($"{nameof(type)}.{nameof(Type.HasElementType)} && {nameof(t
 72925        isMethodParameter,
 72926        typeGenericMap,
 72927        methodGenericMap);
 928
 72929      switch (type)
 930      {
 72931        case Type when type.IsPointer:
 8932          return elementTypeString + "*";
 933
 64934        case Type when type.IsByRef:
 12935          return elementTypeString + "@";
 936
 52937        case Type when type.IsArray:
 52938          int rank = type.GetArrayRank();
 52939          string arrayDimensionsString = rank > 1
 52940            ? "[" + string.Join(",", Enumerable.Repeat("0:", rank)) + "]"
 52941            : "[]";
 52942          return elementTypeString + arrayDimensionsString;
 943
 944        default:
 0945          throw new TowelBugException($"{nameof(GetXmlDocumenationFormattedString)} encountered an unhandled element typ
 946      }
 947    }
 948    else
 327949    {
 327950      string prefaceString = type.IsNested
 327951        ? GetXmlDocumenationFormattedString(
 327952          type.DeclaringType ?? throw new ArgumentException($"{nameof(type)}.{nameof(Type.IsNested)} && {nameof(type)}.{
 327953          isMethodParameter,
 327954          typeGenericMap,
 327955          methodGenericMap) + "."
 327956        : type.Namespace + ".";
 957
 327958      string typeNameString = isMethodParameter
 327959        ? typeNameString = Regex.Replace(type.Name, @"`\d+", string.Empty)
 327960        : typeNameString = type.Name;
 961
 327962      string genericArgumentsString = type.IsGenericType && isMethodParameter
 327963        ? "{" + string.Join(",",
 327964          type.GetGenericArguments().Select(argument =>
 40965            GetXmlDocumenationFormattedString(
 40966              argument,
 40967              isMethodParameter,
 40968              typeGenericMap,
 40969              methodGenericMap))
 327970          ) + "}"
 327971        : string.Empty;
 972
 327973      return prefaceString + typeNameString + genericArgumentsString;
 974    }
 537975  }
 976
 977  internal static string GetXmlNameTypeSegment(string typeFullNameString) =>
 140978    Regex.Replace(typeFullNameString, @"\[.*\]", string.Empty).Replace('+', '.');
 979
 980  #endregion
 981
 982  #region GetXmlDocumentation
 983
 1984  internal static object xmlCacheLock = new();
 1985  internal static ISet<Assembly> loadedAssemblies = SetHashLinked.New<Assembly>();
 1986  internal static MapHashLinked<string, string, StringEquate, StringHash> loadedXmlDocumentation = new();
 987
 988  internal static bool LoadXmlDocumentation(Assembly assembly)
 204989  {
 204990    if (loadedAssemblies.Contains(assembly))
 196991    {
 196992      return false;
 993    }
 8994    bool newContent = false;
 8995    string? directoryPath = assembly.GetDirectoryPath();
 8996    if (directoryPath is not null)
 8997    {
 8998      string xmlFilePath = Path.Combine(directoryPath, assembly.GetName().Name + ".xml");
 8999      if (File.Exists(xmlFilePath))
 71000      {
 71001        using StreamReader streamReader = new(xmlFilePath);
 71002        LoadXmlDocumentationNoLock(streamReader);
 71003        newContent = true;
 71004      }
 81005    }
 81006    loadedAssemblies.Add(assembly);
 81007    return newContent;
 2041008  }
 1009
 1010  /// <summary>Loads the XML code documentation into memory so it can be accessed by extension methods on reflection typ
 1011  /// <param name="xmlDocumentation">The content of the XML code documentation.</param>
 1012  public static void LoadXmlDocumentation(string xmlDocumentation)
 11013  {
 11014    using StringReader stringReader = new(xmlDocumentation);
 11015    LoadXmlDocumentation(stringReader);
 21016  }
 1017
 1018  /// <summary>Loads the XML code documentation into memory so it can be accessed by extension methods on reflection typ
 1019  /// <param name="textReader">The text reader to process in an XmlReader.</param>
 1020  public static void LoadXmlDocumentation(TextReader textReader)
 11021  {
 11022    lock (xmlCacheLock)
 11023    {
 11024      LoadXmlDocumentationNoLock(textReader);
 11025    }
 11026  }
 1027
 1028  internal static void LoadXmlDocumentationNoLock(TextReader textReader)
 81029  {
 81030    using XmlReader xmlReader = XmlReader.Create(textReader);
 11841031    while (xmlReader.Read())
 11761032    {
 11761033      if (xmlReader.NodeType is XmlNodeType.Element && xmlReader.Name is "member")
 10321034      {
 10321035        string? rawName = xmlReader["name"];
 10321036        if (!string.IsNullOrWhiteSpace(rawName))
 10321037        {
 10321038          loadedXmlDocumentation[rawName] = xmlReader.ReadInnerXml();
 10321039        }
 10321040      }
 11761041    }
 161042  }
 1043
 1044  /// <summary>Clears the currently loaded XML documentation.</summary>
 1045  public static void ClearXmlDocumentation()
 91046  {
 91047    lock (xmlCacheLock)
 91048    {
 91049      loadedAssemblies.Clear();
 91050      loadedXmlDocumentation.Clear();
 91051    }
 91052  }
 1053
 1054  internal static string? GetDocumentation(string key, Assembly assembly)
 2761055  {
 2761056    lock (xmlCacheLock)
 2761057    {
 2761058      var (success, _, value) = loadedXmlDocumentation.TryGet(key);
 2761059      if (success)
 2481060      {
 2481061        return value;
 1062      }
 281063      else if (LoadXmlDocumentation(assembly))
 31064      {
 31065        return loadedXmlDocumentation.TryGet(key).Value;
 1066      }
 1067      else
 251068      {
 251069        return null;
 1070      }
 1071    }
 2761072  }
 1073
 1074  /// <summary>Gets the XML documentation on a type.</summary>
 1075  /// <param name="type">The type to get the XML documentation of.</param>
 1076  /// <returns>The XML documentation on the type.</returns>
 1077  /// <remarks>The XML documentation must be loaded into memory for this function to work.</remarks>
 1078  public static string? GetDocumentation(this Type type)
 411079  {
 421080    if (type is null) throw new ArgumentNullException(nameof(type));
 401081    if (sourceof(type.FullName is null, out string c1)) throw new ArgumentException(c1, nameof(type));
 401082    return GetDocumentation(type.GetXmlName(), type.Assembly);
 401083  }
 1084
 1085  /// <summary>Gets the XML documentation on a method.</summary>
 1086  /// <param name="methodInfo">The method to get the XML documentation of.</param>
 1087  /// <returns>The XML documentation on the method.</returns>
 1088  /// <remarks>The XML documentation must be loaded into memory for this function to work.</remarks>
 1089  public static string? GetDocumentation(this MethodInfo methodInfo)
 1081090  {
 1091091    if (methodInfo is null) throw new ArgumentNullException(nameof(methodInfo));
 1071092    if (sourceof(methodInfo.DeclaringType is null, out string c1)) throw new ArgumentException(c1, nameof(methodInfo));
 1071093    return GetDocumentation(methodInfo.GetXmlName(), methodInfo.DeclaringType!.Assembly);
 1071094  }
 1095
 1096  /// <summary>Gets the XML documentation on a constructor.</summary>
 1097  /// <param name="constructorInfo">The constructor to get the XML documentation of.</param>
 1098  /// <returns>The XML documentation on the constructor.</returns>
 1099  /// <remarks>The XML documentation must be loaded into memory for this function to work.</remarks>
 1100  public static string? GetDocumentation(this ConstructorInfo constructorInfo)
 301101  {
 311102    if (constructorInfo is null) throw new ArgumentNullException(nameof(constructorInfo));
 291103    if (sourceof(constructorInfo.DeclaringType is null, out string c1)) throw new ArgumentException(c1, nameof(construct
 291104    return GetDocumentation(constructorInfo.GetXmlName(), constructorInfo.DeclaringType!.Assembly);
 291105  }
 1106
 1107  /// <summary>Gets the XML documentation on a property.</summary>
 1108  /// <param name="propertyInfo">The property to get the XML documentation of.</param>
 1109  /// <returns>The XML documentation on the property.</returns>
 1110  /// <remarks>The XML documentation must be loaded into memory for this function to work.</remarks>
 1111  public static string? GetDocumentation(this PropertyInfo propertyInfo)
 411112  {
 421113    if (propertyInfo is null) throw new ArgumentNullException(nameof(propertyInfo));
 401114    if (sourceof(propertyInfo.DeclaringType is null, out string c1)) throw new ArgumentException(c1, nameof(propertyInfo
 401115    if (sourceof(propertyInfo.DeclaringType!.FullName is null, out string c2)) throw new ArgumentException(c2, nameof(pr
 401116    return GetDocumentation(propertyInfo.GetXmlName(), propertyInfo.DeclaringType.Assembly);
 401117  }
 1118
 1119  /// <summary>Gets the XML documentation on a field.</summary>
 1120  /// <param name="fieldInfo">The field to get the XML documentation of.</param>
 1121  /// <returns>The XML documentation on the field.</returns>
 1122  /// <remarks>The XML documentation must be loaded into memory for this function to work.</remarks>
 1123  public static string? GetDocumentation(this FieldInfo fieldInfo)
 431124  {
 441125    if (fieldInfo is null) throw new ArgumentNullException(nameof(fieldInfo));
 421126    if (sourceof(fieldInfo.DeclaringType is null, out string c1)) throw new ArgumentException(c1, nameof(fieldInfo));
 421127    if (sourceof(fieldInfo.DeclaringType!.FullName is null, out string c2)) throw new ArgumentException(c2, nameof(field
 421128    return GetDocumentation(fieldInfo.GetXmlName(), fieldInfo.DeclaringType.Assembly);
 421129  }
 1130
 1131  /// <summary>Gets the XML documentation on an event.</summary>
 1132  /// <param name="eventInfo">The event to get the XML documentation of.</param>
 1133  /// <returns>The XML documentation on the event.</returns>
 1134  /// <remarks>The XML documentation must be loaded into memory for this function to work.</remarks>
 1135  public static string? GetDocumentation(this EventInfo eventInfo)
 191136  {
 201137    if (eventInfo is null) throw new ArgumentNullException(nameof(eventInfo));
 181138    if (sourceof(eventInfo.DeclaringType is null, out string c1)) throw new ArgumentException(c1, nameof(eventInfo));
 181139    if (sourceof(eventInfo.DeclaringType!.FullName is null, out string c2)) throw new ArgumentException(c2, nameof(event
 181140    return GetDocumentation(eventInfo.GetXmlName(), eventInfo.DeclaringType.Assembly);
 181141  }
 1142
 1143  /// <summary>Gets the XML documentation on a member.</summary>
 1144  /// <param name="memberInfo">The member to get the XML documentation of.</param>
 1145  /// <returns>The XML documentation on the member.</returns>
 1146  /// <remarks>The XML documentation must be loaded into memory for this function to work.</remarks>
 1147  public static string? GetDocumentation(this MemberInfo memberInfo)
 1511148  {
 1511149    switch (memberInfo)
 1150    {
 1151      case FieldInfo fieldInfo:
 231152        if (sourceof(fieldInfo.DeclaringType is null, out string c1)) throw new ArgumentException(c1, nameof(memberInfo)
 231153        if (sourceof(fieldInfo.DeclaringType!.FullName is null, out string c2)) throw new ArgumentException(c2, nameof(m
 231154        return fieldInfo.GetDocumentation();
 1155      case PropertyInfo propertyInfo:
 221156        if (sourceof(propertyInfo.DeclaringType is null, out string c3)) throw new ArgumentException(c3, nameof(memberIn
 221157        if (sourceof(propertyInfo.DeclaringType!.FullName is null, out string c4)) throw new ArgumentException(c4, nameo
 221158        return propertyInfo.GetDocumentation();
 1159      case EventInfo eventInfo:
 91160        if (sourceof(eventInfo.DeclaringType is null, out string c5)) throw new ArgumentException(c5, nameof(memberInfo)
 91161        if (sourceof(eventInfo.DeclaringType!.FullName is null, out string c6)) throw new ArgumentException(c6, nameof(m
 91162        return eventInfo.GetDocumentation();
 1163      case ConstructorInfo constructorInfo:
 151164        if (sourceof(constructorInfo.DeclaringType is null, out string c7)) throw new ArgumentException(c7, nameof(membe
 151165        return constructorInfo.GetDocumentation();
 1166      case MethodInfo methodInfo:
 611167        if (sourceof(methodInfo.DeclaringType is null, out string c8)) throw new ArgumentException(c8, nameof(memberInfo
 611168        return methodInfo.GetDocumentation();
 1169      case Type type:
 201170        if (sourceof(type.FullName is null, out string c9)) throw new ArgumentException(c9, nameof(memberInfo));
 201171        return type.GetDocumentation();
 1172      case null:
 11173        throw new ArgumentNullException(nameof(memberInfo));
 1174      default:
 01175        throw new NotImplementedException($"{nameof(GetDocumentation)} encountered an unhandled {nameof(MemberInfo)} typ
 1176    }
 1501177  }
 1178
 1179  /// <summary>Gets the XML documentation for a parameter.</summary>
 1180  /// <param name="parameterInfo">The parameter to get the XML documentation for.</param>
 1181  /// <returns>The XML documenation of the parameter.</returns>
 1182  public static string? GetDocumentation(this ParameterInfo parameterInfo)
 21183  {
 31184    if (parameterInfo is null) throw new ArgumentNullException(nameof(parameterInfo));
 11185    string? memberDocumentation = parameterInfo.Member.GetDocumentation();
 11186    if (memberDocumentation is not null)
 11187    {
 11188      string regexPattern =
 11189        Regex.Escape($@"<param name=""{parameterInfo.Name}"">") +
 11190        ".*?" +
 11191        Regex.Escape($@"</param>");
 1192
 11193      Match match = Regex.Match(memberDocumentation, regexPattern);
 11194      if (match.Success)
 11195      {
 11196        return match.Value;
 1197      }
 01198    }
 01199    return null;
 11200  }
 1201
 1202  #endregion
 1203
 1204  #region System.Reflection.MethodBase
 1205
 1206  /// <summary>Determines if a method is a local function.</summary>
 1207  /// <param name="methodBase">The method to determine if it is a local function.</param>
 1208  /// <returns>True if the method is a local function. False if not.</returns>
 1209  public static bool IsLocalFunction(this MethodBase methodBase) =>
 261210    Regex.Match(methodBase.Name, @"g__.+\|\d+_\d+").Success;
 1211
 1212  #endregion
 1213}

Methods/Properties

GetTryParseMethod()
GetTryParseMethod(...)
.cctor()
GetFactorialMethod()
GetFactorialMethod(...)
.cctor()
GetIsPrimeMethod()
GetIsPrimeMethod(...)
.cctor()
GetIsNonNegativeMethod()
GetIsNonNegativeMethod(...)
.cctor()
GetIsNegativeMethod()
GetIsNegativeMethod(...)
.cctor()
GetIsPositiveMethod()
GetIsPositiveMethod(...)
.cctor()
GetIsEvenMethod()
GetIsEvenMethod(...)
.cctor()
GetIsOddMethod()
GetIsOddMethod(...)
.cctor()
GetIsIntegerMethod()
GetIsIntegerMethod(...)
.cctor()
GetLessThanMethod()
GetLessThanMethod(...)
.cctor()
GetGreaterThanMethod()
GetGreaterThanMethod(...)
.cctor()
HasImplicitCast()
HasExplicitCast()
HasImplicitCast(...)
HasExplicitCast(...)
HasCast(...)
.cctor()
ConvertToCSharpSource(...)
GetEnumAttribute(...)
GetEnumAttributes(...)
GetLastEnumValue()
GetEventInfosWithAttribute()
GetConstructorInfosWithAttribute()
GetPropertyInfosWithAttribute()
GetFieldInfosWithAttribute()
GetMethodInfosWithAttribute()
GetTypesWithAttribute()
GetDerivedTypes(...)
GetDirectoryPath(...)
GetXmlName(...)
GetXmlName(...)
GetXmlName(...)
GetXmlName(...)
GetXmlName(...)
GetXmlName(...)
GetXmlNameMethodBase(...)
GetXmlDocumenationFormattedString(...)
GetXmlNameTypeSegment(...)
.cctor()
LoadXmlDocumentation(...)
LoadXmlDocumentation(...)
LoadXmlDocumentation(...)
LoadXmlDocumentationNoLock(...)
ClearXmlDocumentation()
GetDocumentation(...)
GetDocumentation(...)
GetDocumentation(...)
GetDocumentation(...)
GetDocumentation(...)
GetDocumentation(...)
GetDocumentation(...)
GetDocumentation(...)
GetDocumentation(...)
IsLocalFunction(...)