문제

We have a custom LocalizedString type used in our domain model. We want to decorate the properties with validation attributes like MaxLength. For this, we added implicit operators to enable casts required by this attribute.

Strangely, the operator seems to never get called and an InvalidCastException get's thrown in the attributes IsValid method. Performing this cast in our own project works.

Is there a special cast behavior compiler magix going on in this system clr ngen'ed attribute or something?

// 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);
}

Thanks for your help.

Edit

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.
도움이 되었습니까?

해결책

Operators of any kind only apply if the type of object is known at compile time. They are not applied "on the fly" to object.

You could try using dynamic which does do that.

Examples:

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!)
    }
}

다른 팁

You write

((Array) value)

But the static type of value is object. So this is compiled as a cast from object to Array. Your conversion operator is never even considered.

Change that to

((Array)(value as LocalizedString))

and you'll be fine.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top