• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

loresoft / FluentCommand / 16300818838

15 Jul 2025 06:03PM UTC coverage: 54.951% (+0.3%) from 54.61%
16300818838

push

github

pwelter34
import data tweaks, xml doc updates

1716 of 3630 branches covered (47.27%)

Branch coverage included in aggregate %.

78 of 143 new or added lines in 11 files covered. (54.55%)

7 existing lines in 5 files now uncovered.

4361 of 7429 relevant lines covered (58.7%)

231.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

13.71
/src/FluentCommand/Reflection/ExpressionFactory.cs
1
using System.Linq.Expressions;
2
using System.Reflection;
3

4
namespace FluentCommand.Reflection;
5

6
/// <summary>
7
/// Provides factory methods for creating delegates to dynamically invoke methods, constructors, properties, and fields using expression trees.
8
/// </summary>
9
internal static class ExpressionFactory
10
{
11
    /// <summary>
12
    /// Creates a delegate that invokes the specified method with the given instance and parameters.
13
    /// </summary>
14
    /// <param name="methodInfo">The method to invoke.</param>
15
    /// <returns>
16
    /// A <see cref="Func{T, TResult}"/> that takes an instance and an array of parameters, and returns the result of the method invocation.
17
    /// For void methods, returns <c>null</c>.
18
    /// </returns>
19
    /// <exception cref="ArgumentNullException">Thrown if <paramref name="methodInfo"/> is <c>null</c>.</exception>
20
    public static Func<object, object[], object> CreateMethod(MethodInfo methodInfo)
21
    {
22
        if (methodInfo == null)
×
23
            throw new ArgumentNullException(nameof(methodInfo));
×
24

25
        // parameters to execute
26
        var instanceParameter = Expression.Parameter(typeof(object), "instance");
×
27
        var parametersParameter = Expression.Parameter(typeof(object[]), "parameters");
×
28

29
        // build parameter list
30
        var parameterExpressions = new List<Expression>();
×
31
        var paramInfos = methodInfo.GetParameters();
×
32
        for (int i = 0; i < paramInfos.Length; i++)
×
33
        {
34
            // (Ti)parameters[i]
35
            var valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i));
×
36

37
            Type parameterType = paramInfos[i].ParameterType;
×
38
            if (parameterType.IsByRef)
×
39
                parameterType = parameterType.GetElementType();
×
40

41
            var valueCast = Expression.Convert(valueObj, parameterType);
×
42

43
            parameterExpressions.Add(valueCast);
×
44
        }
45

46
        // non-instance for static method, or ((TInstance)instance)
47
        var instanceCast = methodInfo.IsStatic ? null : Expression.Convert(instanceParameter, methodInfo.DeclaringType);
×
48

49
        // static invoke or ((TInstance)instance).Method
50
        var methodCall = Expression.Call(instanceCast, methodInfo, parameterExpressions);
×
51

52
        // ((TInstance)instance).Method((T0)parameters[0], (T1)parameters[1], ...)
53
        if (methodCall.Type == typeof(void))
×
54
        {
55
            var lambda = Expression.Lambda<Action<object, object[]>>(methodCall, instanceParameter, parametersParameter);
×
56
            var execute = lambda.Compile();
×
57

58
            return (instance, parameters) =>
×
59
            {
×
60
                execute(instance, parameters);
×
61
                return null;
×
62
            };
×
63
        }
64
        else
65
        {
66
            var castMethodCall = Expression.Convert(methodCall, typeof(object));
×
67
            var lambda = Expression.Lambda<Func<object, object[], object>>(castMethodCall, instanceParameter, parametersParameter);
×
68

69
            return lambda.Compile();
×
70
        }
71
    }
72

73
    /// <summary>
74
    /// Creates a delegate that constructs an instance of the specified type using its parameterless constructor.
75
    /// </summary>
76
    /// <param name="type">The type to instantiate.</param>
77
    /// <returns>A <see cref="Func{TResult}"/> that creates an instance of the specified type.</returns>
78
    /// <exception cref="ArgumentNullException">Thrown if <paramref name="type"/> is <c>null</c>.</exception>
79
    /// <exception cref="ArgumentException">Thrown if the type does not have a parameterless constructor.</exception>
80
    public static Func<object> CreateConstructor(Type type)
81
    {
82
        if (type == null)
×
83
            throw new ArgumentNullException(nameof(type));
×
84

85
        var typeInfo = type.GetTypeInfo();
×
86

UNCOV
87
        var constructorInfo = typeInfo.GetConstructor(Type.EmptyTypes);
×
88
        if (constructorInfo == null)
×
89
            throw new ArgumentException("Could not find constructor for type.", nameof(type));
×
90

91
        var instanceCreate = Expression.New(constructorInfo);
×
92

93
        var instanceCreateCast = typeInfo.IsValueType
×
94
            ? Expression.Convert(instanceCreate, typeof(object))
×
95
            : Expression.TypeAs(instanceCreate, typeof(object));
×
96

97
        var lambda = Expression.Lambda<Func<object>>(instanceCreateCast);
×
98

99
        return lambda.Compile();
×
100
    }
101

102
    /// <summary>
103
    /// Creates a delegate that gets the value of the specified property from an instance.
104
    /// </summary>
105
    /// <param name="propertyInfo">The property to get the value from.</param>
106
    /// <returns>
107
    /// A <see cref="Func{T, TResult}"/> that takes an instance and returns the property value as <c>object</c>,
108
    /// or <c>null</c> if the property is not readable.
109
    /// </returns>
110
    /// <exception cref="ArgumentNullException">Thrown if <paramref name="propertyInfo"/> is <c>null</c>.</exception>
111
    public static Func<object, object> CreateGet(PropertyInfo propertyInfo)
112
    {
113
        if (propertyInfo == null)
94!
114
            throw new ArgumentNullException(nameof(propertyInfo));
×
115

116
        if (!propertyInfo.CanRead)
94!
117
            return null;
×
118

119
        var instance = Expression.Parameter(typeof(object), "instance");
94✔
120
        var declaringType = propertyInfo.DeclaringType;
94✔
121
        var getMethod = propertyInfo.GetGetMethod(true);
94✔
122

123
        var instanceCast = CreateCast(instance, declaringType, getMethod.IsStatic);
94✔
124

125
        var call = Expression.Call(instanceCast, getMethod);
94✔
126
        var valueCast = Expression.TypeAs(call, typeof(object));
94✔
127

128
        var lambda = Expression.Lambda<Func<object, object>>(valueCast, instance);
94✔
129
        return lambda.Compile();
94✔
130
    }
131

132
    /// <summary>
133
    /// Creates a delegate that gets the value of the specified field from an instance.
134
    /// </summary>
135
    /// <param name="fieldInfo">The field to get the value from.</param>
136
    /// <returns>
137
    /// A <see cref="Func{T, TResult}"/> that takes an instance and returns the field value as <c>object</c>.
138
    /// </returns>
139
    /// <exception cref="ArgumentNullException">Thrown if <paramref name="fieldInfo"/> is <c>null</c>.</exception>
140
    public static Func<object, object> CreateGet(FieldInfo fieldInfo)
141
    {
142
        if (fieldInfo == null)
×
143
            throw new ArgumentNullException(nameof(fieldInfo));
×
144

145
        var instance = Expression.Parameter(typeof(object), "instance");
×
146
        var declaringType = fieldInfo.DeclaringType;
×
147

148
        var instanceCast = CreateCast(instance, declaringType, fieldInfo.IsStatic);
×
149

150
        var fieldAccess = Expression.Field(instanceCast, fieldInfo);
×
151
        var valueCast = Expression.TypeAs(fieldAccess, typeof(object));
×
152

153
        var lambda = Expression.Lambda<Func<object, object>>(valueCast, instance);
×
154
        return lambda.Compile();
×
155
    }
156

157
    /// <summary>
158
    /// Creates a delegate that sets the value of the specified property on an instance.
159
    /// </summary>
160
    /// <param name="propertyInfo">The property to set the value on.</param>
161
    /// <returns>
162
    /// An <see cref="Action{T1, T2}"/> that takes an instance and a value to set,
163
    /// or <c>null</c> if the property is not writable.
164
    /// </returns>
165
    /// <exception cref="ArgumentNullException">Thrown if <paramref name="propertyInfo"/> is <c>null</c>.</exception>
166
    public static Action<object, object> CreateSet(PropertyInfo propertyInfo)
167
    {
168
        if (propertyInfo == null)
×
169
            throw new ArgumentNullException(nameof(propertyInfo));
×
170

171
        if (!propertyInfo.CanWrite)
×
172
            return null;
×
173

174
        var instance = Expression.Parameter(typeof(object), "instance");
×
175
        var value = Expression.Parameter(typeof(object), "value");
×
176

177
        var declaringType = propertyInfo.DeclaringType;
×
178
        var propertyType = propertyInfo.PropertyType;
×
179
        var setMethod = propertyInfo.GetSetMethod(true);
×
180

181
        var instanceCast = CreateCast(instance, declaringType, setMethod.IsStatic);
×
182
        var valueCast = CreateCast(value, propertyType, false);
×
183

184
        var call = Expression.Call(instanceCast, setMethod, valueCast);
×
185
        var parameters = new[] { instance, value };
×
186

187
        var lambda = Expression.Lambda<Action<object, object>>(call, parameters);
×
188
        return lambda.Compile();
×
189
    }
190

191
    /// <summary>
192
    /// Creates a delegate that sets the value of the specified field on an instance.
193
    /// </summary>
194
    /// <param name="fieldInfo">The field to set the value on.</param>
195
    /// <returns>
196
    /// An <see cref="Action{T1, T2}"/> that takes an instance and a value to set.
197
    /// </returns>
198
    /// <exception cref="ArgumentNullException">Thrown if <paramref name="fieldInfo"/> is <c>null</c>.</exception>
199
    public static Action<object, object> CreateSet(FieldInfo fieldInfo)
200
    {
201
        if (fieldInfo == null)
×
202
            throw new ArgumentNullException(nameof(fieldInfo));
×
203

204
        var instance = Expression.Parameter(typeof(object), "instance");
×
205
        var value = Expression.Parameter(typeof(object), "value");
×
206

207
        var declaringType = fieldInfo.DeclaringType;
×
208
        var fieldType = fieldInfo.FieldType;
×
209

210
        var instanceCast = CreateCast(instance, declaringType, fieldInfo.IsStatic);
×
211
        var valueCast = CreateCast(value, fieldType, false);
×
212

213
        var member = Expression.Field(instanceCast, fieldInfo);
×
214
        var assign = Expression.Assign(member, valueCast);
×
215

216
        var parameters = new[] { instance, value };
×
217

218
        var lambda = Expression.Lambda<Action<object, object>>(assign, parameters);
×
219
        return lambda.Compile();
×
220
    }
221

222
    /// <summary>
223
    /// Creates a cast expression for the given parameter and type, handling static and value types appropriately.
224
    /// </summary>
225
    /// <param name="instance">The parameter expression representing the instance or value.</param>
226
    /// <param name="declaringType">The type to cast to.</param>
227
    /// <param name="isStatic">Indicates whether the member is static.</param>
228
    /// <returns>
229
    /// A <see cref="UnaryExpression"/> representing the cast, or <c>null</c> if the member is static.
230
    /// </returns>
231
    private static UnaryExpression CreateCast(ParameterExpression instance, Type declaringType, bool isStatic)
232
    {
233
        if (isStatic)
94!
234
            return null;
×
235

236
        // value as T is slightly faster than (T)value, so if it's not a value type, use that
237
        if (declaringType.GetTypeInfo().IsValueType)
94!
238
            return Expression.Convert(instance, declaringType);
×
239
        else
240
            return Expression.TypeAs(instance, declaringType);
94✔
241
    }
242
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc