C# 从"byte"类型转换为"generic" "K"类型



我通过读取二进制文件作为ReadByte()的唯一参数在c#中创建了huffman树。之后,我通过该二进制文件中每个符号的重复次数计算每个symbol的频率。我存储了processingValue中读取的字节,最初是"int"类型(在我尝试将其变为"K"类型后,我的意思是generic,之后会产生问题)。但直到一切顺利。请参阅下面的代码:

  public class Node
        {
            public Node next, left, right;
            public int symbol; //After i will make it generic by putting "K" at the place of "int"
            public int freq;
            public int is_processed;
        }
        public Node front, rear;

这个huffman是构造函数,上面和下面的函数定义都在huffman类中。

                while (stream.BaseStream.Position < stream.BaseStream.Length) 
                {
                    int processingValue = stream.ReadByte(); //The problem is here when i tried to do Func<byte,K>
                    {
                        Node pt, temp;
                        bool is_there = false;
                        pt = front;
                        while (pt != null) 
                        {
                            if (pt.symbol == processingValue) //The problem is here it can's compare "byte" to "K" type.
                            {
                                pt.freq++;
                                is_there = true;
                                break;
                            }
                            temp = pt;
                            pt = pt.next;
                        }
                        if (is_there == false) 
                        {
                            temp = new Node();
                            temp.symbol = processingValue;
                            temp.freq = 1;
                            temp.left = null;
                            temp.right = null;
                            temp.next = null;
                            temp.is_processed = 0;
                            if (front == null) 
                            {
                                front = temp;
                            } 
                            else 
                            {
                                temp.next = front;
                                front = temp;
                            }
                        }
                    }
                }
                stream.Close();
                //////////////////////////////
            }
        }

当我尝试将此"symbol"作为类型为"K"的generic时,会出现问题。我将Huffman类更改为如下所示:

         public class Node
        {
            public Node next, left, right;
            public K symbol; // "int" is replaced by "K"
            public int freq;
            public int is_processed;
            }
        public Node front, rear;

现在创建的问题是,当我使用ReadByte()读取字节时,我将其保存在我的代码中称为"processingValue"的"int"类型变量中。我现在将"int"替换为"K"以使其通用。但是当我这样做时,我有一个错误,说不可能从字节到"K"的对话。有人可以给我等效的代码,以便使"int"类型的processingValue适用于generic类型的"K",因为"symbol"还必须在32/64位架构上为"短"/"乌龙"等工作,以读取二进制文件,通过计算该二进制文件中存在的符号的重复来创建频率。我也尝试了Func<byte, K> (Func<byte, K> processingValue = stream.ReadByte();),但它给出了错误:

error CS0029: Cannot implicitly convert type `byte' to `System.Func<byte,K>'

编辑:我已经改变了代码为Func,但没有错误的编译,但是在执行"mono filename.exe binaryFile.bin"//我正在计算这个二进制文件中符号的频率。(时间符号重复的次数是它的频率),我有未处理的异常:请参阅下面的错误:(它只是打印"check1",而不是"check2"在我的代码的构造函数中给出的错误)

hp@ubuntu:~/Desktop/Internship_Xav/templatescplus$ gmcs test.cshp@ubuntu:~/Desktop/Internship_Xav/templatescplus$ mono test.exe toto.bin check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
check1
Unhandled Exception: System.ArgumentException: Destination array is not long enough to copy all the items in the collection. Check array index and length.
  at System.BitConverter.PutBytes (System.Byte* dst, System.Byte[] src, Int32 start_index, Int32 count) [0x00000] in <filename unknown>:0 
  at System.BitConverter.ToInt64 (System.Byte[] value, Int32 startIndex) [0x00000] in <filename unknown>:0 
  at shekhar_final_version_Csharp.Huffman`1[System.Int64]..ctor (System.String[] args, System.Func`3 converter) [0x00000] in <filename unknown>:0 
  at shekhar_final_version_Csharp.MyClass.Main (System.String[] args) [0x00000] in <filename unknown>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: System.ArgumentException: Destination array is not long enough to copy all the items in the collection. Check array index and length.
  at System.BitConverter.PutBytes (System.Byte* dst, System.Byte[] src, Int32 start_index, Int32 count) [0x00000] in <filename unknown>:0 
  at System.BitConverter.ToInt64 (System.Byte[] value, Int32 startIndex) [0x00000] in <filename unknown>:0 
  at shekhar_final_version_Csharp.Huffman`1[System.Int64]..ctor (System.String[] args, System.Func`3 converter) [0x00000] in <filename unknown>:0 
  at shekhar_final_version_Csharp.MyClass.Main (System.String[] args) [0x00000] in <filename unknown>:0 
hp@ubuntu:~/Desktop/Internship_Xav/templatescplus$

嗯,错误确切地说明了问题所在-编译器不知道如何将byte转换为实现IComparable<K>的随机K。你根本做不到,因为它几乎可以是任何东西。

如果你想要一个由符号类型参数化的通用霍夫曼树,那么你需要

  1. 让用户提供已经读取并转换为适当类型的符号
  2. 让用户提供一个函数,将byte转换为他们选择的K(即Func<K, byte>),然后您的读取代码可以使用
一般来说,我实际上推荐前者,因为它鼓励关注点分离。将I/O构建到数据结构类中通常不是一个好主意,因为这样一来,您就会陷入这种困境,并且以后无法从不同的源中读取数据。选项2将允许您尽可能地保持与现有代码的接近。

解决方案比仅仅将K转换为字节或其他方式要复杂一些。

这里有一个方法。

定义一个接口ICanLoadFromStream,继承IComparable,然后将该接口作为k的where子句,然后在接口方法LoadFromStream(stream)中代替stream.ReadByte()调用:

public interface ICanLoadFromStream: IComparable{
   void LoadFromStream(Stream stream);
}
public class Huffman<K> where K :  ICanLoadFromStream{
...
}

明显的复杂性是,即使对于byte, int等,您也必须实现包装器类。

注意:记住,不是所有的流类型实现长度或位置(网络流),重构你的代码来做一个Read。

您的Func<>方法是这样做的一种方法,但是您得到错误的原因是因为您试图将ReadByte的结果分配给Func,而不是调用Func来进行转换。

假设你有一个类型为K,那么你将有一个Func像这样:

Func<byte,K> converter = b=>new K(b);

现在你只需读取字节并将其传入:

byte byteValue = stream.ReadByte();
K kValue = converter(byteValue);

您需要将转换器传递给Huffman<K>构造函数并将其存储在成员变量中:

public Huffman(Func<byte,K> converter)
{
  m_Converter = converter;
}

这样做的原因是您不能使用泛型类型参数的参数化构造函数创建实例。你只能调用它们的默认构造函数

我终于设法解决了这个问题。解决方案是我的条件while (stream.BaseStream.Position < stream.BaseStream.Length),当文件的最后读取不是的倍数(或小于所选择的数据类型的大小,然后它给出未处理的异常)。

我通过将while()循环改为for循环来解决这个问题,如下所示:

int size = Marshal.SizeOf(typeof (T));    
long length = stream.BaseStream.Length;
for (long position = 0; position + size < length; position += size)
{
  //other stuffs   
}

相关内容

最新更新