1

我们的域模型中使用了自定义的LocalizedString类型。我们要装饰具有验证属性的属性,如MaxLength。为此,我们添加了隐式运算符以启用此属性所需的强制转换。未通过属性调用的隐式/显式转换运算符(System.ComponentModel.DataAnnotation.dll)

奇怪的是,运算符似乎永远不会被调用,并且在属性IsValid方法中抛出InvalidCastException get。在我们自己的项目中进行演员制作。

是否有一个特殊的强制性行为编译器magix在这个系统中执行clr ngen'ed属性或者什么?

// 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 = "123456789" }; 

    // Act 
    var valid = attribute.IsValid(localized); 

    // Assert 
    Assert.IsFalse(valid); 
} 

感谢您的帮助。

编辑

Das Objekt des Typs "Nexplore.ReSearch.Base.Core.Domain.Model.LocalizedString" kann nicht in Typ "System.Array" umgewandelt werden. 
bei System.ComponentModel.DataAnnotations.MaxLengthAttribute.IsValid(Object value) 
bei Nexplore.ReSearch.Base.Tests.Unit.Infrastructure.CodeFirst.MaxLengthLocalizedAttributeTests.CanCallIsValidWithLocalizedString() in d:\Nexplore\SourceForge\Nexplore.ReSearch.Base\Source\Nexplore.ReSearch.Base.Tests.Unit\Infrastructure.CodeFirst\MaxLengthLocalizedAttributeTests.cs:Zeile 40. 

回答

9

运营商的任何一种的只有当对象的类型在编译时是已知的适用。他们不是“动态地”应用到object

可能尝试使用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!) 
    } 
} 
+1

+1我必须读两遍,直到我看到“这是一个类型检查”!所以将未知类型的对象转换为其他类型的唯一方法是使用IConvertible? –

+1

@Adriano我不确定我会过度倾向于'IConvertible',但确实是*类似的东西,是的 –

+0

谢谢,现在很多其他的东西变得清晰了! :-O –

1

你写

((Array) value) 

但静态类型的值对象。所以这被编译为从对象到阵列的强制转换。你的转换操作符从来没有被考虑过。

改变,要

((Array)(value as LocalizedString)) 

,你会没事的。

+0

除非LocalizedString是定义隐式转换运算符的私有类。我使用由反序列化过程产生的私有Int64Proxy类(JSON.NET不能从两部分的高/低值中反序列化为像Int64这样的值类型结构,所以我必须创建一个引用类型的代理类,它可以是通过高和低部分的两个单独分配来初始化)。从动态对象读取时,隐式运算符可以工作,但如果必须通过IDictionary测试其存在性,则不能将结果对象转换为Int64Proxy,因为它是私有类。 – Triynko

+0

只有“动态”对象才会正确地查找并调用Int64Proxy类上的隐式运算符,因为由于ExpandoObject在请求不存在的字段值时抛出错误而不是返回undefined或null,所以我不得不使用'IDictionary '接口尝试获取一个普通的旧对象值,其隐式操作符不能被调用,除非我第一次转换为Int64Proxy,这是我不能做的,因为它是一个私有类。 – Triynko