-
Notifications
You must be signed in to change notification settings - Fork 479
Expand file tree
/
Copy pathCastExtensions.cs
More file actions
131 lines (119 loc) · 4.2 KB
/
CastExtensions.cs
File metadata and controls
131 lines (119 loc) · 4.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
using System;
#if NET8_0_OR_GREATER
using System.Diagnostics.CodeAnalysis;
#endif
using System.Linq;
using System.Reflection;
namespace CommandLine
{
internal static class CastExtensions
{
private const string ImplicitCastMethodName = "op_Implicit";
private const string ExplicitCastMethodName = "op_Explicit";
public static bool CanCast<T>(
#if NET8_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
#endif
this Type baseType)
{
return baseType.CanImplicitCast<T>() || baseType.CanExplicitCast<T>();
}
#if NET8_0_OR_GREATER
[UnconditionalSuppressMessage("Missing annotations on type", "IL2072")]
#endif
public static bool CanCast<T>(this object obj)
{
var objType = obj.GetType();
return objType.CanCast<T>();
}
public static T Cast<T>(this object obj)
{
try
{
return (T)obj;
}
catch (InvalidCastException)
{
if (obj.CanImplicitCast<T>())
return obj.ImplicitCast<T>();
if (obj.CanExplicitCast<T>())
return obj.ExplicitCast<T>();
else
throw;
}
}
private static bool CanImplicitCast<T>(
#if NET8_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
#endif
this Type baseType)
{
return baseType.CanCast<T>(ImplicitCastMethodName);
}
#if NET8_0_OR_GREATER
[UnconditionalSuppressMessage("Missing annotations on type", "IL2072")]
#endif
private static bool CanImplicitCast<T>(this object obj)
{
var baseType = obj.GetType();
return baseType.CanImplicitCast<T>();
}
private static bool CanExplicitCast<T>(
#if NET8_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
#endif
this Type baseType)
{
return baseType.CanCast<T>(ExplicitCastMethodName);
}
#if NET8_0_OR_GREATER
[UnconditionalSuppressMessage("Missing annotations on type", "IL2072")]
#endif
private static bool CanExplicitCast<T>(this object obj)
{
var baseType = obj.GetType();
return baseType.CanExplicitCast<T>();
}
private static bool CanCast<T>(
#if NET8_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
#endif
this Type baseType,
string castMethodName)
{
var targetType = typeof(T);
return baseType.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(mi => mi.Name == castMethodName && mi.ReturnType == targetType)
.Any(mi =>
{
ParameterInfo pi = mi.GetParameters().FirstOrDefault();
return pi != null && pi.ParameterType == baseType;
});
}
private static T ImplicitCast<T>(this object obj)
{
return obj.Cast<T>(ImplicitCastMethodName);
}
private static T ExplicitCast<T>(this object obj)
{
return obj.Cast<T>(ExplicitCastMethodName);
}
#if NET8_0_OR_GREATER
[UnconditionalSuppressMessage("Reflection on object", "IL2075")]
#endif
private static T Cast<T>(this object obj, string castMethodName)
{
var objType = obj.GetType();
MethodInfo conversionMethod = objType.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(mi => mi.Name == castMethodName && mi.ReturnType == typeof(T))
.SingleOrDefault(mi =>
{
ParameterInfo pi = mi.GetParameters().FirstOrDefault();
return pi != null && pi.ParameterType == objType;
});
return conversionMethod != null
? (T)conversionMethod.Invoke(null, new[] { obj })
: throw new InvalidCastException($"No method to cast {objType.FullName} to {typeof(T).FullName}");
}
}
}