Can't Cast to String Even With Operator Overloaded

Using MVC3 and the StringLength validation attribute on a property of type MyType<string> who's internal value is a string , I get an exception:

Unable to cast object of type 'MyType' to type 'System.String'.

So I added an operator overload, here's my class:

public class MyType<T>
{
    public T Value { get; set; }
    //...

    public static implicit operator string(MyType<T> instance)
    {
        //Return the internal value of the instance.
        return Convert.ToString(instance.Value);
    }
}

So this should, in theory, allow MyType to be cast to a String . However, I still get the same error, here is the stack trace:

[InvalidCastException: Unable to cast object of type 'MyType' to type 'System.String'.]
System.ComponentModel.DataAnnotations.StringLengthAttribute.IsValid(Object value) +64
System.ComponentModel.DataAnnotations.ValidationAttribute.IsValid(Object value, ValidationContext validationContext) +176
System.ComponentModel.DataAnnotations.ValidationAttribute.GetValidationResult(Object value, ValidationContext validationContext) +41
System.Web.Mvc.d__1.MoveNext() +267

The StringLengthAttribute.IsValid method (from the .NET framework, not my code) is doing this:

public override bool IsValid(object value)
{
    this.EnsureLegalLengths();
    int num = (value == null) ? 0 : ((string)value).Length;
    return value == null || (num >= this.MinimumLength && num <= this.MaximumLength);
}

Seems like it should work, what am I missing?


The variable value is declared of type object . You must first cast to the actual type first since the underlying object is not a string . There are no conversions defined from object to other types so the cast you're doing is effectively telling the compiler that this object is actually a string when it is not. This is essentially the same kind of rule that must be followed when unboxing value types.

By casting it to your type first, the compiler can then realize that a (implicit) conversion exists from your type to the desired string type and can generate the appropriate instructions.

eg,

object obj = new MyObject<string> { Value = "Foobar" };
string x = (string)obj;           // fail: obj is not a string
string y = (MyObject<string>)obj; // obj: obj is cast to MyObject<string> and
                                  //      an implicit cast to string exists
// to be clearer
string z = (string)(MyObject<string>)obj;

public override bool IsValid(object value)
{
    this.EnsureLegalLengths();
    int num = (value == null) ? 0 : ((MyType<string>)value).Value.Length;
    return value == null || (num >= this.MinimumLength && num <= this.MaximumLength);
}

Don't cast it to string , but to MyType<string> .

The changed line of code to reflect this is:

    int num = (value == null) ? 0 : ((MyType<string>)value).Value.Length;

Edit : Don't pass MyType<string> to the method, pass MyType<string>.Value to it so that cast will be successful.


You are using implicit cast and you should do explicit cast because the framework cast it explicitly. Like this:

(string)value

You should add:

public static explicit operator string(MyType<T> instance)
{
    //Return the internal value of the instance.
    return Convert.ToString(instance.Value);
}
链接地址: http://www.djcxy.com/p/71062.html

上一篇: 使用NHibernate查询'时间'字段时无效的转换异常

下一篇: 即使运算符重载也无法强制转换为字符串