IConvertable.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
  2. using System;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. namespace Animancer
  6. {
  7. /// <summary>An object which can be converted to another type.</summary>
  8. /// https://kybernetik.com.au/animancer/api/Animancer/IConvertable_1
  9. public interface IConvertable<out T>
  10. {
  11. /************************************************************************************************************************/
  12. /// <summary>Returns the equivalent of this object as <typeparamref name="T"/>.</summary>
  13. T Convert();
  14. /************************************************************************************************************************/
  15. }
  16. /// <summary>Utility methods for <see cref="IConvertable{T}"/>.</summary>
  17. /// https://kybernetik.com.au/animancer/api/Animancer/ConvertableUtilities
  18. public static partial class ConvertableUtilities
  19. {
  20. /************************************************************************************************************************/
  21. /// <summary>
  22. /// Custom conversion functions used as a fallback
  23. /// for types that can't implement <see cref="IConvertable{T}"/>.
  24. /// </summary>
  25. public static readonly Dictionary<Type, Func<object, Type, object>>
  26. CustomConverters = new();
  27. /************************************************************************************************************************/
  28. /// <summary>Tries to convert the `original` to <typeparamref name="T"/>.</summary>
  29. /// <remarks>
  30. /// <list type="bullet">
  31. /// <item>If the `original` is already a <typeparamref name="T"/> then it's returned directly.</item>
  32. /// <item>Or if it's an <see cref="IConvertable{T}"/> then <see cref="IConvertable{T}.Convert"/> is used.</item>
  33. /// <item>Otherwise, this method throws an <see cref="ArgumentException"/>.</item>
  34. /// </list>
  35. /// </remarks>
  36. public static T ConvertOrThrow<T>(object original)
  37. {
  38. if (TryConvert<T>(original, out var converted))
  39. return converted;
  40. throw new ArgumentException(
  41. $"Unable to convert '{AnimancerUtilities.ToStringOrNull(original)}'" +
  42. $" to '{typeof(T).GetNameCS()}'.");
  43. }
  44. /************************************************************************************************************************/
  45. /// <summary>Tries to convert the `original` to <typeparamref name="T"/>.</summary>
  46. /// <remarks>
  47. /// <list type="bullet">
  48. /// <item>If the `original` is already a <typeparamref name="T"/> then it's returned directly.</item>
  49. /// <item>Or if it's an <see cref="IConvertable{T}"/> then <see cref="IConvertable{T}.Convert"/> is used.</item>
  50. /// <item>Otherwise, this method returns the <c>default(T)</c>.</item>
  51. /// </list>
  52. /// </remarks>
  53. public static T ConvertOrDefault<T>(object original)
  54. {
  55. TryConvert<T>(original, out var converted);
  56. return converted;
  57. }
  58. /************************************************************************************************************************/
  59. /// <summary>Tries to convert the `original` to <typeparamref name="T"/>.</summary>
  60. /// <remarks>
  61. /// <list type="bullet">
  62. /// <item>If the `original` is already a <typeparamref name="T"/> then it's returned directly.</item>
  63. /// <item>Or if it's an <see cref="IConvertable{T}"/> then <see cref="IConvertable{T}.Convert"/> is used.</item>
  64. /// <item>Otherwise, this method returns <c>false</c>.</item>
  65. /// </list>
  66. /// </remarks>
  67. public static bool TryConvert<T>(object original, out T converted)
  68. {
  69. if (original is null)
  70. {
  71. converted = default;
  72. return converted == null;// True for value type, false for reference type.
  73. }
  74. if (original is T t)
  75. {
  76. converted = t;
  77. return true;
  78. }
  79. if (original is IConvertable<T> convertable)
  80. {
  81. converted = convertable.Convert();
  82. return true;
  83. }
  84. if (CustomConverters.TryGetValue(original.GetType(), out var converter))
  85. {
  86. converted = (T)converter(original, typeof(T));
  87. return converted != null;
  88. }
  89. converted = default;
  90. return false;
  91. }
  92. /************************************************************************************************************************/
  93. /// <summary>Initializes the inbuilt custom converters.</summary>
  94. static ConvertableUtilities()
  95. {
  96. CustomConverters.Add(typeof(GameObject), TryGetComponent);
  97. }
  98. /************************************************************************************************************************/
  99. /// <summary>Tries to get a component if the `original` is a <see cref="GameObject"/>.</summary>
  100. private static object TryGetComponent(object original, Type type)
  101. {
  102. if (original is GameObject gameObject &&
  103. gameObject.TryGetComponent(type, out var component))
  104. return component;
  105. return null;
  106. }
  107. /************************************************************************************************************************/
  108. }
  109. }