c#从“byte”类型转换为“generic”“K”类型

时间:2014-03-20 12:36:08

标签: c# algorithm generics data-structures

我使用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类中。

                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();
                //////////////////////////////
            }
        }

当我尝试制作这个&#34; symbol&#34;作为类型&#34; generic&#34;的K。我按如下方式更改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()读取字节时,我将其保存在&#34; int&#34;类型变量名为&#34; processingValue&#34;在我的代码中。我现在更换了&#34; int&#34;到&#34; K&#34;使它通用。但是,当我这样做时,我有一个错误,说从Byte到&#34; K&#34; 没有可能的对话。 有人可以给我相应的代码,以便制作&#34; int&#34;键入processingValuegeneric类型"K",因为"symbol"也必须适用于&#34;短&#34; /&#34; ulong&#34; 32/64位架构上的等等,通过计算该二进制文件中存在的符号的重复来读取二进制文件以创建频率。 我还尝试了Func<byte, K>Func<byte, K> processingValue = stream.ReadByte();),但却出错:

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

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

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$

4 个答案:

答案 0 :(得分:1)

嗯,错误确切地说明了问题所在 - 编译器不知道如何将byte转换为实现K的随机IComparable<K>。你根本无法做到,因为它可能或多或少。

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

  1. 让用户为您提供已读入并转换为相应类型的符号
  2. 让用户提供一个功能,将byte转换为您选择的K(即Func<K, byte>),然后您的阅读代码可以使用
  3. 实际上,我实际上推荐前者,因为它鼓励分离关注点。将I / O构建到数据结构类中通常是一个坏主意,因为那样你就会坚持下去并且以后不能从不同的源读取。选项2允许您尽可能接近现有代码。

答案 1 :(得分:1)

解决方案比将K转换为字节或其他方式更复杂。

这是一种方法。

定义一个继承自IComparable的接口ICanLoadFromStream,然后将该接口作为K的where子句。然后在接口方法stream.ReadByte()中调用LoadFromStream(stream):< / p>

public interface ICanLoadFromStream: IComparable{
   void LoadFromStream(Stream stream);
}

public class Huffman<K> where K :  ICanLoadFromStream{
...
}

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

注意:请记住,并非所有流类型都实现长度或位置(网络流),重新构建代码以执行读取。

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

最后我设法解决了这个问题。 解决方案是我的条件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   
}