如何根据给定的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;
}
答案 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
)。