c# - 用 Pascal 编写与 C# 代码等效的代码

标签 c# .net delphi

我正在尝试将此 Pascal 代码转换为 C#。没有编译错误,并且该方法适用于短字符串(4 或 5 个字符)。所有的方法和函数都是等价的,但我的代码抛出这个异常:

System.OverflowException: Value was either too large or too small for a character .

这是 StackTrace:

in System.Convert.ToChar(Int32 value) in ConsoleApplication3.Program.Encrypt(Boolean encrypt, String word, Int32 startKey, Int32 multKey, Int32 addKey) on c:\Users\TRS\Documents\Visual Studio 2013\Projects\ConsoleApplication3\ConsoleApplication3\Program.cs:line 29 .

这是 Pascal 代码:

function TGenericsF.Encrypter(Encrypt: WordBool; Source: AnsiString;
  StartKey, MultKey, AddKey: Integer): AnsiString;
 {$R-} {$Q-}
 var Counter: LongInt;
   S: AnsiString;
   Ret: AnsiString;
   begin
     S := Source;
     Ret := '';
     for Counter := 1 to Length(S) do
     begin
       if Encrypt then
        begin
         Ret := Ret + AnsiChar(Ord(S[Counter]) xor (StartKey shr 8));
         StartKey := (Ord(Ret[Counter]) + StartKey) * MultKey + AddKey;
        end
     else
       begin
         Ret := Ret + AnsiChar(Ord(S[Counter]) xor (StartKey shr 8));
         StartKey := (Ord(S[Counter]) + StartKey) * MultKey + AddKey;
       end;
    end;
  Result := Ret;
end;

这是我等效的 C# 代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication3
{
   class Program
   {
    static void Main(string[] args)
    {
        string username = Encrypt(true, "Administrator", 8, 12, 16);
        Console.WriteLine(username);
        Console.ReadKey();
    }

    public static string Encrypt(bool encrypt, string word, int startKey, int multKey, int addKey)
    {
         string encryptedWord = string.Empty;

         for (int i = 0; i < word.Length; i++)
         {
             if(encrypt)
             {

                 encryptedWord += Convert.ToChar(word[i] ^ (startKey >> 8));
                 startKey = (((int)encryptedWord[i]) + startKey) * multKey + addKey;

             }
             else
             {
                 encryptedWord += Convert.ToChar(word[i] ^ (startKey >> 8));
                 startKey = (((int)word[i]) + startKey) * multKey + addKey;
             }
         }

        return encryptedWord;
    }
}
}

非常感谢。

最佳答案

解决此问题的第一步是认识到加密对字节数组进行操作,并返回字节数组。这里没有字符串的位置。文本编码只是模糊了加密算法。如果您需要加密一个字符串,您必须首先使用一些明确定义的文本编码将其转换为字节数组。

那么,让我们用该策略重写 Delphi 代码。它看起来像这样:

{$R-} {$Q-}
function EncryptDecrypt(Encrypt: Boolean; const Source: TBytes;
  StartKey, MultKey, AddKey: Integer): TBytes;
var
  i: Integer;
begin
  SetLength(Result, Length(Source));
  for i := low(Source) to high(Source) do
  begin
    if Encrypt then
    begin
      Result[i] := Source[i] xor (StartKey shr 8);
      StartKey := (Result[i] + StartKey) * MultKey + AddKey;
    end
    else
    begin
      Result[i] := Source[i] xor (StartKey shr 8);
      StartKey := (Source[i] + StartKey) * MultKey + AddKey;
    end;
  end;
end;

在 C# 中复制它很容易。我们只需要确保以与 Delphi 代码相同的方式允许溢出。这涉及使用 unchecked。代码运行如下:

public static byte[] EncryptDecrypt(bool Encrypt, byte[] Source,
    int StartKey, int MultKey, int AddKey)
{
    byte[] Dest = new byte[Source.Length];
    for (int i = 0; i < Source.Length; i++)
    {
        if (Encrypt)
        {
            unchecked
            {
                Dest[i] = (byte) (Source[i] ^ (StartKey >> 8));
                StartKey = (Dest[i] + StartKey) * MultKey + AddKey;
            }
        }
        else
        {
            unchecked
            {
                Dest[i] = (byte) (Source[i] ^ (StartKey >> 8));
                StartKey = (Source[i] + StartKey) * MultKey + AddKey;
            }
        }
    }
    return Dest;
}

我粗略的测试表明:

  1. 字节数组 Delphi 代码的行为与问题中的 Delphi 代码相同。
  2. C# 代码的行为与 Delphi 代码相同。
  3. 两个版本的代码code都可以忠实地解密加密数组。

您的代码导致错误,因为已检查算术是否有溢出。您的算术溢出了 int 数据类型,因为它是在检查的上下文中执行的,所以溢出会导致错误。文档有详细信息:http://msdn.microsoft.com/en-us/library/khy08726.aspx

unchecked 关键字抑制该错误并允许发生溢出。 Delphi 代码使用 {$Q-} 来达到同样的效果。

关于c# - 用 Pascal 编写与 C# 代码等效的代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23809545/

相关文章:

c# - lambda 回调或直接回调之间的 Blazor 区别

c# - 大型数据集的内存消耗

c# - 亚马逊API订单履行Feed不更新订单数据

c# - 使用 Image.FromStream 返回图像

delphi - 更改复选框状态而不调用 OnClick 事件

DELPHI - 如何使用 opendialog1 选择文件夹?

c# - 加密引擎

c# - 可以在 C# 4.0 中创建多类型 lambda 函数的单一多类型集合吗?

c# - 当 .NET 核心 API 返回带有 XSRF-TOKEN 的响应时,Angular(客户端)未将 XSRF-TOKEN 添加到 cookie

Delphi、VirtualStringTree - 处理简单的文本样式(如 bbcode)