【发布时间】:2021-08-27 00:44:04
【问题描述】:
我正在尝试验证我的 Unity MonoBehavior,以便在脚本设置不正确时更加明显。我从我所做的其他 C# 工作中了解到 FluentValidation,因此我为 Unity 设置了 Nuget 并安装了它。
问题在于,当 MonoBehavior 上的 GameObject 未初始化时,由于 Unity 的行为覆盖,FluentValidation 的表达式会抛出错误而不是返回 null。
我试图通过创建一个扩展方法来解决这个问题,该方法将捕获表达式中抛出的任何异常并返回 null。我不熟悉使用 Expression 类构建表达式,但我不确定该怎么做。运行它会导致编辑器控制台中出现以下错误:
InvalidOperationException: No coercion operator is defined between types 'System.Func`2[DialogController,UnityEngine.GameObject]' and 'UnityEngine.GameObject'.
System.Linq.Expressions.Expression.GetUserDefinedCoercionOrThrow (System.Linq.Expressions.ExpressionType coercionType, System.Linq.Expressions.Expression expression, System.Type convertToType) (at <351e49e2a5bf4fd6beabb458ce2255f3>:0)
System.Linq.Expressions.Expression.Convert (System.Linq.Expressions.Expression expression, System.Type type, System.Reflection.MethodInfo method) (at <351e49e2a5bf4fd6beabb458ce2255f3>:0)
System.Linq.Expressions.Expression.Convert (System.Linq.Expressions.Expression expression, System.Type type) (at <351e49e2a5bf4fd6beabb458ce2255f3>:0)
ValidationExtensions.SafeRuleFor[T,TProperty] (FluentValidation.AbstractValidator`1[T] validator, System.Linq.Expressions.Expression`1[TDelegate] expression) (at Assets/Scripts/ValidationExtensions.cs:12)
DialogControllerValidation.WhenAsync (System.Func`3[T1,T2,TResult] predicate, System.Action action) (at Assets/Scripts/DialogControllerValidation.cs:10)
DialogController.OnValidate () (at Assets/Scripts/DialogController.cs:170)
这是我的 MonoBehavior:
public class DialogController: MonoBehavior {
public GameObject content;
private void OnValidate()
{
new DialogControllerValidation().ValidateAndThrow(this);
}
}
这是我的验证器类:
public class DialogControllerValidation : AbstractValidator<DialogController>
{
public DialogControllerValidation()
{
this.SafeRuleFor(x => x.content).NotNull();
}
}
这是我的扩展方法:
public static class ValidationExtensions
{
public static IRuleBuilderInitial<T, TProperty> SafeRuleFor<T, TProperty>(this AbstractValidator<T> validator,
Expression<Func<T, TProperty>> expression)
{
var tryExpression = Expression.TryCatch(
Expression.Block(typeof(TProperty), Expression.Convert(expression, typeof(TProperty))),
Expression.Catch(typeof(TProperty), Expression.Constant(null))
);
return validator.RuleFor(Expression.Lambda<Func<T, TProperty>>(
tryExpression,
Expression.Parameter(typeof(T), "t")
)
);
}
}
编辑:如果我将Expression.Convert(expression, typeof(TProperty)) 替换为expression,即:
public static class ValidationExtensions
{
public static IRuleBuilderInitial<T, TProperty> SafeRuleFor<T, TProperty>(this AbstractValidator<T> validator,
Expression<Func<T, TProperty>> expression)
{
var tryExpression = Expression.TryCatch(
Expression.Block(typeof(TProperty), expression),
Expression.Catch(typeof(TProperty), Expression.Constant(null))
);
return validator.RuleFor(Expression.Lambda<Func<T, TProperty>>(
tryExpression,
Expression.Parameter(typeof(T), "t")
)
);
}
}
那么我得到的错误是
ArgumentException: Argument types do not match
System.Linq.Expressions.Expression.BlockCore (System.Type type, System.Collections.ObjectModel.ReadOnlyCollection`1[T] variables, System.Collections.ObjectModel.ReadOnlyCollection`1[T] expressions) (at <351e49e2a5bf4fd6beabb458ce2255f3>:0)
System.Linq.Expressions.Expression.Block (System.Type type, System.Collections.Generic.IEnumerable`1[T] variables, System.Collections.Generic.IEnumerable`1[T] expressions) (at <351e49e2a5bf4fd6beabb458ce2255f3>:0)
System.Linq.Expressions.Expression.Block (System.Type type, System.Collections.Generic.IEnumerable`1[T] expressions) (at <351e49e2a5bf4fd6beabb458ce2255f3>:0)
System.Linq.Expressions.Expression.Block (System.Type type, System.Linq.Expressions.Expression[] expressions) (at <351e49e2a5bf4fd6beabb458ce2255f3>:0)
ValidationExtensions.SafeRuleFor[T,TProperty] (FluentValidation.AbstractValidator`1[T] validator, System.Linq.Expressions.Expression`1[TDelegate] expression) (at Assets/Scripts/ValidationExtensions.cs:12)
DialogControllerValidation.WhenAsync (System.Func`3[T1,T2,TResult] predicate, System.Action action) (at Assets/Scripts/DialogControllerValidation.cs:10)
DialogController.OnValidate () (at Assets/Scripts/DialogController.cs:170)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&)
【问题讨论】:
-
"在类型 'System.Func``2[DialogController,UnityEngine.GameObject]' 和 'UnityEngine.GameObject' 之间没有定义强制运算符",因为这就是您在这里所要求的;
Expression.Convert(expression, typeof(TProperty))。您的意思是调用该方法吗? -
@JeremyLakeman 我在看this SO 答案。如果我不包含
Expression.Convert()而只使用expression,则会收到“参数类型不匹配”错误。 (请参阅我的编辑。)我的意图是使用Expression.Convert()将两个表达式更改为具有相同的类型。 -
你可能想要的是重用
expression.Body&expression.Parameters。但是控制流和返回值有点奇怪(例如stackoverflow.com/questions/13687914/…)。
标签: c# unity3d fluentvalidation