首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将Wrapper<Derived>转换为Wrapper<Base>

将Wrapper<Derived>转换为Wrapper<Base>
EN

Stack Overflow用户
提问于 2016-06-28 06:17:34
回答 3查看 222关注 0票数 2

我有这样的代码:

代码语言:javascript
复制
class Base { }

class Derived : Base { }

class Wrapper<T> {

    public T Value { get; }

    public Wrapper (T value) { Value = value; }
}

我想这样使用Wrapper

代码语言:javascript
复制
Wrapper<Base> wrapper = new Wrapper<Derived> (new Derived ());

但最后却出现了这样的错误:

错误CS0029不能隐式地将类型‘包装’转换为‘包装’。

我尝试在Wrapper class中创建用作转换器的方法。

代码语言:javascript
复制
public Wrapper<TResult> To<TResult> () /* Constraints needed here. */ =>
    new Wrapper<TResult> (Value);

但我错过了一些有效的约束。当前代码以错误结束:

S1503参数1:不能从“T”转换为“TResult”

我可以想象To方法上的约束可能类似于where T : TResult,但这不是有效的约束。

有什么方法可以很容易地实现从Wrapper<Derived>Wrapper<Base>的转换器?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-06-28 06:26:39

您可以使用这样的协方差:

代码语言:javascript
复制
class Base { }

class Derived : Base { }

interface IWrapper<out T>
{
    T Value { get; }
}

class Wrapper<T> : IWrapper<T>
{
    public T Value { get; private set; }

    public Wrapper(T value) { Value = value; }
}

class Program
{
    static void Main(string[] args)
    {
        IWrapper<Base> wrapper = new Wrapper<Derived>(new Derived());
    }
}
票数 4
EN

Stack Overflow用户

发布于 2016-06-28 06:21:54

首先,我会在类中添加一个约束,要求T必须是Base类型。

代码语言:javascript
复制
class Base { }
class Derived : Base { }

class Wrapper<T> where T : Base // T must be (derived from) Base
{
    public T Value { get; }

    public Wrapper (T value) { Value = value; }
}

其次,通用转换器将是危险的。如果有人试图将Wrapper<Gnu>转换为Wrapper<Lion>怎么办?

所以我会后退一步,做一个非通用的转换器,它可以简单地转换成Wrapper<Base>

代码语言:javascript
复制
public Wrapper<Base> ToBase()
{
     return new Wrapper<Base>(Value);    
}

这是因为T在类级别上的约束。

C#实际上是一种以高级别的类型安全性而闻名的语言。但你可以绕开它,做你在评论中要求做的事情,方法是放弃任何限制,只需尝试抛出任何东西:

代码语言:javascript
复制
public Wrapper<TResult> To<TResult>() where TResult : class
{
     return new Wrapper<TResult>(Value as TResult);    
}

您需要class约束和as操作符,因为两个泛型参数之间的直接转换是不可编译的(因为IL太依赖于特定类型)。

但是,如果类型不匹配,这将返回Wrapper实例,并将Value设置为null。它也将使用派生类型而不是基类型。所以保重。你可以为此加一些额外的支票。并照顾那侏儒:)

更新:

更安全的方法:

代码语言:javascript
复制
public Wrapper<TResult> To<TResult>() where TResult : class// TResult must also be (derived from) Base
{
    if (!typeof(TResult).IsAssignableFrom(typeof(T)))
        throw new InvalidCastException();
    return new Wrapper<TResult>(Value as TResult);
}

这将检查T是否从TResult派生,如果不是,则抛出一个InvalidCastException。你可以根据你的需要改进它。

票数 3
EN

Stack Overflow用户

发布于 2016-06-28 06:45:14

您遇到的问题是,泛型类型Wrapper<Base>Wrapper<Derived>是.NET框架的两个完全不同的类

您可以做的是创建一个新的Wrapper类型为Base

代码语言:javascript
复制
Wrapper<Base> wrapper = new Wrapper<Base>(new Derived());

或者完成您的方法方法:

代码语言:javascript
复制
public Wrapper<TResult> To<TResult>() where TResult : T 
    => new Wrapper<TResult>( (TResult)Value ); // This could throw an error

public bool TryCastTo<TResult>(out Wrapper<TResult> derivedWrapper) where TResult : T
{
    derivedWrapper = null;

    // EDIT: changed to the version from René Vogt since this is much cleaner and mine had a little error
    if (!typeof(T).IsAssignableFrom(typeof(TResult)))
    {
        return false;
    }

    derivedWrapper = new Wrapper<TResult>( (TResult)Value );
    return true;
}

其用途如下:

代码语言:javascript
复制
Wrapper<Derived> derivedWrapper1 = wrapper.To<Derived>();
Wrapper<Derived> derivedWrapper2;
bool success = wrapper.TryCastTo<Derived>(out derivedWrapper2);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38068393

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档