简体   繁体   English

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

[英]Safely cast a Generic type in C#

How can I safely cast and return m_obj depending on the given Generic type. 如何根据给定的泛型类型安全地强制转换并返回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;
}

I know that if instead if m_obj I had a list I could simply do this: 我知道,如果相反,如果m_obj我有一个列表,我可以简单地做到这一点:

private readonly IList<Object> m_objects;

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

But I cannot find a solution for the former code. 但是我找不到以前的代码的解决方案。

public interface IObject
{

}

My answer: 我的答案:

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

The as keyword works with reference types. as关键字适用于引用类型。

The compiler doesn't know that T is indeed a reference type, so it shouts at you and won't compile. 编译器不知道T确实是引用类型,因此它会向您喊叫并且不会编译。
You can tell the compiler that it's a reference type by adding the class constraint before the IObject constraint. 通过在IObject约束之前添加class约束 ,可以告诉编译器它是引用类型。 Now you can safely cast. 现在您可以放心了。

The as operator is reserved for reference types. as运算符保留用于引用类型。 If T is always a reference type, the solution is to add a class constraint to TryGetAs<T> . 如果T始终是引用类型,则解决方案是向TryGetAs<T>添加class约束。 If T can also be a value type, this is not an option. 如果T也可以是值类型,则这不是选项。 In this case you can use the is operator: 在这种情况下,可以使用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;
    }
}

In C# 7.0 you can simplify it like this (and improve performance since you don't need an is cast and then another type cast): 在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;
    }
}
public bool TryGetAs<T>(out T value) where T : class, IObject
{
    value = m_obj as T;

    return (value != null);
}

will act the same as your final solution, as well as likely being faster (since a null check is faster than an is check). 将与最终解决方案一样,并且可能更快(因为空检查比is检查更快)。

There is no benefit in not including the class modifier, if all of your IObject implementations are reference types ( class ) not value types ( struct ). 如果所有IObject实现都是引用类型( class )而不是值类型( struct ), 则不包括class修饰符没有任何好处。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM