C# 属性未调用隐式/显式转换运算符(System.ComponentModel.DataAnnotation.dll)
我们在域模型中使用了自定义本地化字符串类型。我们希望使用验证属性来装饰属性,如C# 属性未调用隐式/显式转换运算符(System.ComponentModel.DataAnnotation.dll),c#,data-annotations,implicit-conversion,explicit-conversion,C#,Data Annotations,Implicit Conversion,Explicit Conversion,我们在域模型中使用了自定义本地化字符串类型。我们希望使用验证属性来装饰属性,如MaxLength。为此,我们添加了隐式运算符以启用此属性所需的强制转换 奇怪的是,操作符似乎从未被调用,并且在attributesIsValid方法中抛出了InvalidCastException get。在我们自己的项目工程中执行此强制转换 在这个系统clr ngen'ed属性或其他东西中是否有一个特殊的强制转换行为编译器magix // Custom type public class LocalizedStri
MaxLength
。为此,我们添加了隐式运算符以启用此属性所需的强制转换
奇怪的是,操作符似乎从未被调用,并且在attributesIsValid
方法中抛出了InvalidCastException get。在我们自己的项目工程中执行此强制转换
在这个系统clr ngen'ed属性或其他东西中是否有一个特殊的强制转换行为编译器magix
// Custom type
public class LocalizedString
{
public string Value
{
get { return string.Empty; }
}
public static implicit operator Array(LocalizedString localizedString)
{
if (localizedString.Value == null)
{
return new char[0];
}
return localizedString.Value.ToCharArray();
}
}
// Type: System.ComponentModel.DataAnnotations.MaxLengthAttribute
// Assembly: System.ComponentModel.DataAnnotations, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.ComponentModel.DataAnnotations.dll
public override bool IsValid(object value)
{
this.EnsureLegalLengths();
if (value == null)
{
return true;
}
else
{
string str = value as string;
int num = str == null ? ((Array) value).Length : str.Length;
if (-1 != this.Length)
return num <= this.Length;
else
return true;
}
}
[TestMethod]
public void CanCallIsValidWithLocalizedString()
{
// Arrange
var attribute = new MaxLengthAttribute(20);
var localized = new LocalizedString { Value = "123456789012345678901" };
// Act
var valid = attribute.IsValid(localized);
// Assert
Assert.IsFalse(valid);
}
任何类型的运算符仅在编译时已知对象类型时才适用。它们不会“动态”应用于对象
您可以尝试使用dynamic
这样做
示例:
using System;
class Foo
{
public static implicit operator Array(Foo foo)
{
return new int[0]; // doesn't matter
}
static void Main()
{
Foo foo = new Foo();
Array x = (Array)foo; // implicit operator called via compiler
dynamic dyn = foo;
Array y = (Array)dyn; // implicit operator called via dynmic
object obj = foo;
Array z = (Array)obj; // implicit operator NOT called
// - this is a type-check (BOOM!)
}
}
你写
((Array) value)
但是静态类型的值是object。因此,这被编译为从对象到数组的转换。您的转换运算符从未被考虑过
换成
((Array)(value as LocalizedString))
你会没事的。+1我不得不读了两遍,直到我看到“这是一个类型检查”!因此,从未知类型的对象转换为其他对象的唯一方法是使用IConvertible?@Adriano我不确定我是否会过于倾向于
IConvertible
,但事实上是这样的,是的,在这种情况下,我们可能必须创建自己的自定义LocalizedMaxLength属性来处理LocalizedString?还有其他方法吗?遇到了这个问题。我的反序列化例程返回一个Int64Proxy对象,当从动态ExpandObject字段读取时,会调用其隐式Int64运算符。但是,由于ExpandoObject在不存在时尝试访问该值时会抛出错误,因此必须首先将ExpandoObject强制转换为IDictionary并调用TryGetValue,该函数返回一个“object”。尽管对象的基础类型是包含隐式强制转换运算符的Int64Proxy,但这种普通“对象”类型不能隐式强制转换。所以,是的,动态工作。如果字段不存在,ExpandoObject究竟为什么会抛出错误。它是一个动态对象,应该有一个明确的值,如Flash/AS3的“undefined”,以区别于现有的空值。由于客户端可能包含也可能不包含我要查找的值(这是可选的),我不能只写,如果(data.optionalField!=未定义)
,我必须写对象字段值;if((数据为IDictionary).TryGetValue(“optionalField”,out fieldValue))
等,除非LocalizedString是定义隐式转换运算符的私有类。我使用一个私有Int64代理类,该类是反序列化过程的结果(JSON.NET无法从两部分高/低值反序列化为值类型结构,如Int64,因此我必须创建一个引用类型代理类,该类可以通过高/低部分的两个单独赋值进行初始化)。从动态对象读取时,隐式运算符可以工作,但如果我必须通过IDictionary测试其存在性,则生成的对象无法强制转换为Int64Proxy,因为它是一个私有类。只有“动态”对象才能正确查找并调用我的Int64Proxy类上的隐式运算符,因此,由于ExpandooObject在请求不存在的字段值时会抛出错误,而不是返回undefined或null,因此我不得不使用IDictionary
接口尝试获取一个普通的旧对象值,除非我首先强制转换到Int64Proxy,否则无法调用其隐式运算符,因为它是一个私有类。
((Array)(value as LocalizedString))