Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/266.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从泛型类型显式转换为其类型参数的对象_C#_Generics_Casting - Fatal编程技术网

C# 从泛型类型显式转换为其类型参数的对象

C# 从泛型类型显式转换为其类型参数的对象,c#,generics,casting,C#,Generics,Casting,我想创建一个validable类,它在概念上类似于Nullable。我有一个被许多类型使用的IValidatable接口,但是如果一个类型还没有实现这个接口,我希望能够很容易地在它周围放置一个包装器,然后使用该包装器来存储验证错误 我希望能够转换回包装的对象,但是转换失败了,即使我有一个显式操作符集(尽管实际上我更喜欢隐式操作符)。以下是定义: public interface IValidatable { bool IsValid { get; }

我想创建一个
validable
类,它在概念上类似于
Nullable
。我有一个被许多类型使用的
IValidatable
接口,但是如果一个类型还没有实现这个接口,我希望能够很容易地在它周围放置一个包装器,然后使用该包装器来存储验证错误

我希望能够转换回包装的对象,但是转换失败了,即使我有一个显式操作符集(尽管实际上我更喜欢隐式操作符)。以下是定义:

    public interface IValidatable
    {
        bool IsValid { get; }
        void Validate();
        // (more validation-related methods here...)
    }

    public class Validatable<T> : IValidatable
        where T : class
    {
        public Validatable(T obj)
        {
            Object = obj;
        }

        public T Object { get; private set; }

        public bool IsValid { get; set; }

        public void Validate()
        {

        }

        public static implicit operator Validatable<T>(T other)
        {
            return new Validatable<T>(other);
        }

        public static explicit operator T(Validatable<T> other)
        {
            return other.Object;
        }

    }

    public static class Validatable
    {
        public static IValidatable AsValidatable<T>(T obj)
            where T: class
        {
            if (obj == null)
                return null;

            var already = obj as IValidatable;

            return already ?? new Validatable<T>(obj);
        }
    }

    public class Person // not IValidatable
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

为什么对因InvalidCastException而失败的人员进行强制转换?

A
Validable。AsValidable
返回
IValidatable
,而不是
Validable
,没有强制转换。显然,不能保证
IValidatable
的实例也是
validable
的实例

如果忽略
asvalidable
并在另一个方向上使用cast操作符(尽管很好):

    public static void ConversionTest()
    {
        var person = new Person { FirstName = "Bob", LastName = "Smith" };

        var validatable = (Validatable<Person>)person;           

        var cast = (Person)validatable; // FAILS here with InvalidCastException
    }
publicstaticvoidconversiontest()
{
var person=newperson{FirstName=“Bob”,LastName=“Smith”};
var validatable=(validatable)个人;
var cast=(Person)validatable;//此处失败,出现InvalidCastException
}

对于
Nullable
他们作弊-这是一个特例。

这是因为
IValidatable
不能转换为
Person
——只有
可以验证。编译器将插入一个简单的强制转换,并且无法调用运算符,因为它不知道具体的类型


作为您尝试执行的替代方法,您可以使用
比较器
IComparable
:实现
验证器。默认值
提供一个
验证器
,该验证器将使用对象自己的
IValidatable
实现,或者构造另一个。这样,就不需要将对象强制转换回来,因为概念仍然是分开的。

如果您明确地拼写出类型,问题就会变得很明显:

public void ConversionTest()
{
    Personperson = new Person { FirstName = "Bob", LastName = "Smith" };

    IValidatable validatable = Validatable.AsValidatable(person);

    Person cast = (Person)validatable; // FAILS here with InvalidCastException
}
由于
validable
具有接口类型,因此无法应用转换运算符(在
validable
中声明)


Nullable
具有特殊的运行时支持以启用此场景。

隐式和显式转换运算符永远不会对接口求值。如果希望将类型为
IValidatable
的引用转换为某种类型的引用(希望是底层对象的引用),则
IValidatable
必须包含一个返回内容的属性[我建议避免使用名称
object
]作为类型
System.Object
的引用,或者使用泛型方法
T GetContentAs()
,该方法将尝试以特定类型返回内容。两者都不会提供公共类型安全性,但在使用非泛型接口时,这是意料之中的


或者,您可以使用类型为
T
的只读
Content
属性创建协变接口
IValidatable
接口。无法使用casting操作符从
IValidatable
Foo
提取内容,但是你可以简单地使用
IValidatable.Content
属性。

我投票赞成保留它,因为这个问题还涉及到Nullable如何支持它。@erikkallen:
Nullable
在语言规范/编译器中不是特例吗?@AndreyAkinshin我查看了这个问题和其他许多问题使用casting泛型类型,但我不相信它们中的任何一个都能解决这个问题,因为
IValidatable
接口的使用似乎是我在这里遇到的问题。你不能在validable上公开原始对象吗?类似于
validable.getUnderground()
这在技术上并没有错,但OP定义了一个转换运算符来支持它,所以问题更多的是为什么转换运算符不工作。感谢您的解释。为了回答你的问题,我确实考虑了这些问题,但这只是一个捏造的例子来证明这个问题;在我的实际代码中,我不想区分实际实现了
IValidatable
的类型和由
Validatable
包装的类型。我猜“启用此场景的特殊运行时支持”是让我有点困惑的地方,感谢您的澄清。顺便说一句,编译器的消息是“无法将“Validatable`1[Person]”类型的对象强制转换为“Person”类型。所以这里看起来真的很混乱;它应该是“无法将'IValidatable'类型的对象强制转换为'Person'类型”。无论如何,接受这个,因为我认为这是最清楚的答案,谢谢。不是编译器给你错误消息,而是运行时。我所说的特殊支持是,当运行时将一个null值装箱时,它将被装箱为null或底层值。嗯,
比较器
/
IComparable
解决方案听起来很有趣,但不幸的是,它可能会涉及更改太多现有代码,使其在我的特定情况下变得不实用。谢谢你的想法,不过,我可能会进一步探讨。。。
public void ConversionTest()
{
    Personperson = new Person { FirstName = "Bob", LastName = "Smith" };

    IValidatable validatable = Validatable.AsValidatable(person);

    Person cast = (Person)validatable; // FAILS here with InvalidCastException
}