在C#中安全地转换Generic类型

时间:2017-11-26 11:19:25

标签: c# generics casting oftype

如何根据给定的Generic类型安全地转换和返回m_obj。

private IObject m_obj;
public bool TryGetAs<T>(out T value) where T :IObject
{
    value = m_obj as T; // The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint

    // value = (T)m_obj; This compiles!

    if (value != null)
        return true;

    return false;
}

我知道如果相反,如果m_obj我有一个列表,我可以简单地这样做:

private readonly IList<Object> m_objects;

internal IList<T> Collect<T>() where T : IObject
{
    return m_objects.OfType<T>().ToList();
}

但是我找不到前代码的解决方案。

public interface IObject
{

}

我的回答:

    public bool TryGetAs<T>(out T value) where T :IObject
    {
        value = default(T);
        if (!(m_obj is T))
            return false;

        value = (T)m_obj;
        return true;
    }

3 个答案:

答案 0 :(得分:3)

as关键字适用于引用类型。

编译器不知道T确实是一个引用类型,所以它会对你大喊大叫而不会编译。
您可以通过在IObject约束之前添加class constraint来告诉编译器它是引用类型。现在你可以安全地施展。

答案 1 :(得分:1)

as运算符是为引用类型保留的。如果T始终是引用类型,则解决方案是向class添加TryGetAs<T>约束。如果T也可以是值类型,则这不是一个选项。在这种情况下,您可以使用is运算符:

public bool TryGetAs<T>(out T value) where T : IObject
{
    if(m_obj is T)
    {
        value = (T)m_obj;
        return true;
    }
    else
    {
        value = default(T);
        return false;
    }
}

在C#7.0中,您可以像这样简化它(并提高性能,因为您不需要is强制转换,然后再进行其他类型转换):

public bool TryGetAs<T>(out T value) where T : IObject
{
    if(m_obj is T tValue)
    {
        value = tValue;
        return true;
    }
    else
    {
        value = default(T);
        return false;
    }
}

答案 2 :(得分:-2)

public bool TryGetAs<T>(out T value) where T : class, IObject
{
    value = m_obj as T;

    return (value != null);
}

将与最终解决方案相同,并且可能更快(因为空检查比is检查更快)。

如果您的所有class实施都是引用类型(IObject)而不是值,则包括class修饰符没有任何好处类型(struct)。