forked from ServiceStack/ServiceStack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathExtensions.cs
More file actions
172 lines (145 loc) · 7.35 KB
/
Extensions.cs
File metadata and controls
172 lines (145 loc) · 7.35 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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#region License
// Copyright (c) Jeremy Skinner (http://www.jeremyskinner.co.uk)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// The latest version of this file can be found at http://www.codeplex.com/FluentValidation
#endregion
namespace ServiceStack.FluentValidation.Internal
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text.RegularExpressions;
using Validators;
/// <summary>
/// Useful extensions
/// </summary>
public static class Extensions {
internal static void Guard(this object obj, string message) {
if (obj == null) {
throw new ArgumentNullException(message);
}
}
internal static void Guard(this string str, string message) {
if (string.IsNullOrEmpty(str)) {
throw new ArgumentNullException(message);
}
}
/// <summary>
/// Gets a MemberInfo from a member expression.
/// </summary>
public static MemberInfo GetMember(this LambdaExpression expression) {
var memberExp = RemoveUnary(expression.Body);
if (memberExp == null) {
return null;
}
return memberExp.Member;
}
/// <summary>
/// Gets a MemberInfo from a member expression.
/// </summary>
public static MemberInfo GetMember<T, TProperty>(this Expression<Func<T, TProperty>> expression) {
var memberExp = RemoveUnary(expression.Body);
if (memberExp == null) {
return null;
}
return memberExp.Member;
}
private static MemberExpression RemoveUnary(Expression toUnwrap) {
if (toUnwrap is UnaryExpression) {
return ((UnaryExpression)toUnwrap).Operand as MemberExpression;
}
return toUnwrap as MemberExpression;
}
/// <summary>
/// Splits pascal case, so "FooBar" would become "Foo Bar"
/// </summary>
public static string SplitPascalCase(this string input) {
if (string.IsNullOrEmpty(input)) {
return input;
}
return Regex.Replace(input, "([A-Z])", " $1").Trim();
}
/// <summary>
/// Helper method to construct a constant expression from a constant.
/// </summary>
/// <typeparam name="T">Type of object being validated</typeparam>
/// <typeparam name="TProperty">Type of property being validated</typeparam>
/// <param name="valueToCompare">The value being compared</param>
/// <returns></returns>
internal static Expression<Func<T, TProperty>> GetConstantExpresionFromConstant<T, TProperty>(TProperty valueToCompare) {
Expression constant = Expression.Constant(valueToCompare, typeof(TProperty));
ParameterExpression parameter = Expression.Parameter(typeof(T), "t");
return Expression.Lambda<Func<T, TProperty>>(constant, parameter);
}
internal static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
foreach(var item in source) {
action(item);
}
}
/// <summary>
/// Based on a child validator and a propery rule, infers whether the validator should be wrapped in a ChildValidatorAdaptor or a CollectionValidatorAdaptor
/// </summary>
internal static IPropertyValidator InferPropertyValidatorForChildValidator(PropertyRule rule, IValidator childValidator) {
// If the property implements IEnumerable<T> and the validator validates T, assume it's a collection property validator
// This is here for backwards compatibility with v2. V3 uses the new SetCollectionValidator method.
if (DoesImplementCompatibleIEnumerable(rule.TypeToValidate, childValidator)) {
return new ChildCollectionValidatorAdaptor(childValidator);
}
// Otherwise if the validator is allowed to validate the type, assume child validator
if (childValidator.CanValidateInstancesOfType(rule.TypeToValidate)) {
return new ChildValidatorAdaptor(childValidator);
}
throw new InvalidOperationException(string.Format("The validator '{0}' cannot validate members of type '{1}' - the types are not compatible.", childValidator.GetType().Name, rule.TypeToValidate.Name));
}
private static bool DoesImplementCompatibleIEnumerable(Type propertyType, IValidator childValidator) {
//concatenate the property type itself, incase we're using IEnumerable directly (typeof(IEnumerable).GetInterfaces() obviously doesn't include IEnumerable)
var interfaces = from i in propertyType.GetInterfaces().Concat(new[] { propertyType })
where i.IsGenericType
where i.GetGenericTypeDefinition() == typeof(IEnumerable<>)
let enumerableType = i.GetGenericArguments()[0]
where childValidator.CanValidateInstancesOfType(enumerableType)
select i;
return interfaces.Any();
}
public static Func<object, object> CoerceToNonGeneric<T, TProperty>(this Func<T, TProperty> func) {
return x => func((T)x);
}
public static Func<object, bool> CoerceToNonGeneric<T>(this Func<T, bool> func) {
return x => func((T)x);
}
public static Action<object> CoerceToNonGeneric<T>(this Action<T> action) {
return x => action((T)x);
}
#if WINDOWS_PHONE
// WP7 doesn't support expression tree compilation.
// As a workaround, this extension method falls back to delegate compilation.
// However, it only supports simple property references, ie x => x.SomeProperty
internal static TDelegate Compile<TDelegate>(this Expression<TDelegate> expression) {
var compiledDelegate = CompilePropertyGetterExpression(expression, typeof(TDelegate));
return (TDelegate)compiledDelegate;
}
static object CompilePropertyGetterExpression(LambdaExpression expression, Type delegateType) {
var member = expression.GetMember() as PropertyInfo;
if (member == null) {
throw new NotSupportedException("FluentValidation for WP7 can only be used with expressions that reference public properties, ie x => x.SomeProperty");
}
var compiledDelegate = Delegate.CreateDelegate(delegateType, member.GetGetMethod());
return compiledDelegate;
}
#endif
}
}