简体   繁体   English

泛型的C#转换错误

[英]C# casting error on generics

I have a C# method where I am trying to use generics as: 我有一个C#方法,尝试将generics用作:

unsafe private void PerformWindowLevel<T>(int lower, int upper, ref T[] pixels)

Somewhere along the function I have the following line: 在函数的某处,我有以下内容:

float shift = ... // some value
float scale = ... // some value
float val = ((float)pixels[i] + shift) * scale;

Here I get the error Cannot convert type 'T' to 'float' . 在这里,我收到错误消息Cannot convert type 'T' to 'float'

The method is called as: 该方法称为:

PerformWindowLevel<byte>(10, 100, ref pixels);

So I am converting a byte type to float which should be possible. 所以我正在将byte类型转换为浮点数,这应该是可能的。 pixels is a byte array declared as public byte[] pixels; pixels是声明为public byte[] pixels;的字节数组public byte[] pixels; and filled with valid values. 并填充有效值。

The problem is that T doesn´t know anything about what it might be in your calling code, it´s just a generic type-parameter, that could also be string or whatever which you (apparently) can´t cast to float . 问题是T对调用代码中的内容一无所知,它只是一个通用的类型参数,也可以是string ,也可以是您(显然)无法转换为float You´d need a generic constraint: 您需要一个通用约束:

unsafe private void PerformWindowLevel<T>(int lower, int upper, ref T[] pixels) where T: float

This still doesn´t work as you can´t use a struct (which float is) as generic type-parameter. 这仍然无法正常工作,因为您无法将结构( float )用作通用类型参数。 Only interfaces or classes are allowed. 仅允许使用接口或类。

However this would only allow float to be a valid generic parameter making the term generic quite - well - ungeneric . 但是,这只会使float成为有效的泛型参数,从而使术语泛型非常不泛型 This is why generics are completely wrong in your case. 这就是为什么泛型在您的情况下完全错误的原因。 When only one or two types are possible you should create a concrete method (or an overload) for that specific type. 如果只有一种或两种类型,则应为该特定类型创建一个具体方法(或重载)。 Generics on the other side state that every type (that satisfies the generic constraint which is indicated by a where ) is possible, not just one. 另一方面,泛型指出,每种类型(满足用where指示的泛型约束)都是可能的,而不仅仅是一种。

You need to write a Seperate TypeConverter as at Compile Time the Compiler is unaware of Type T and whether it can be converted to float . 您需要编写一个单独的TypeConverter,因为在编译时编译器不知道T类型以及它是否可以转换为float类型。

you can use Convert.ChangeType Method to Convert 您可以使用Convert.ChangeType方法进行转换

public class ConvertTypeClass<T1,T2>
    {
        public T1 ConvertMethod(T2 val)
        {
            return (T1) (Convert.ChangeType(val, typeof(T1)));
        }
    } 

Cannot convert type 'T' to 'float' indicates that the compiler simply doesn't know exactly what kind of data type that generic type parameter T currently has. 无法将类型'T'转换为'float'表示编译器完全不知道泛型类型参数T当前具有哪种数据类型。 Any attempt to cast T to other type except for object (as base class of all objects) will result InvalidCastException . 任何将T InvalidCastExceptionobject (其他object基类)以外的其他类型的尝试都将导致InvalidCastException

Hence, based from how generic type parameter works as explained above, the code can be written as this: 因此,根据上述通用类型参数的工作方式,代码可以这样编写:

unsafe private void PerformWindowLevel<T>(int lower, int upper, ref T[] pixels)
{
    float shift = 3.0F; // some value
    float scale = 5.0F; // some value
    float val = (Convert.ToSingle((object)pixels[i]) + shift) * scale;
}

or include a check for byte data type before performing cast: 或在执行强制转换之前包含对byte数据类型的检查:

unsafe private void PerformWindowLevel<T>(int lower, int upper, ref T[] pixels)
{
    if (typeof(T) == typeof(byte))
    {
        float shift = 3.0F; // some value
        float scale = 5.0F; // some value
        float val = (Convert.ToSingle((object)pixels[i]) + shift) * scale;
    }
}

Note that the generic itself should be completely independent of the type, so if type parameter T intended to just accept byte just use ref byte[] pixels instead. 请注意,泛型本身应完全独立于类型,因此,如果类型参数T打算仅接受byte ,则请使用ref byte[] pixels代替。

NB: About the message A type used as a constraint must be an interface, a non-sealed class or a type parameter , it can be explained where float ( System.Single ) itself is just a struct , which is implicitly sealed . 注意:关于消息用作约束的类型必须是接口,未密封的类或类型参数 ,可以解释为floatSystem.Single )本身只是一个struct (隐式sealed A struct or sealed class can't be used as generic type parameter constraint, but you can constrain that T is a struct . 不能将struct或密封类用作通用类型参数约束,但是可以约束T 为struct Currently valid constraints should be like this: 当前有效的约束应如下所示:

void GenericMethod<T>() where T: class // reference type constraint

void GenericMethod<T>() where T: struct {} // value type constraint

void GenericMethod<T>() where T: new() // public parameterless constructor constraint

void GenericMethod<T>() where T: IConvertible // interface constraint

void GenericMethod<T>() where T: BaseClass // base class constraint

More info: Constraints on Type Parameters 更多信息: 类型参数的约束

Similar issues: 类似问题:

Cannot implicitly convert type 'T' to 'Int' 无法将类型“ T”隐式转换为“ Int”

Value of type 'T' cannot be converted to 类型“ T”的值不能转换为

This is a known problem given that the basic arithmetic types do not have a common interface (eg INumeric) which you could use to restrict your method, via where T : INumeric. 鉴于基本算术类型没有公共接口(例如,INumeric),可通过T:INumeric来限制您的方法,因此这是一个已知问题。

There is, however, a slightly clumsy workaround, which does compile! 但是,有一个稍微笨拙的解决方法,可以编译! If you include your code within a typeof condition, the compiler is happy. 如果将代码包含在typeof条件中,则编译器很高兴。 For example: 例如:

private void PerformWindowLevel<T>(int lower, int upper, ref T[] pixels) 
{
    if ((typeof(T) == typeof(byte)) || (typeof(T) == typeof(int)))
    {
        float shift = 1;
        float scale = 2;
        float val = ((float)(object)pixels[0] + shift) * scale;
    }  
}

All you need to do, is to include in your surrounding if condition, as many types as you need! 您需要做的就是,如果需要的话,将其包含在您的周围环境中! As I say a bit clumsy, but it works! 正如我所说的那样笨拙,但它有效!

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

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