การแปล C# เป็น Java – โดยใช้ตรรกะ .NET Framework ในสภาพแวดล้อม Java

การแปลโปรเจ็กต์จากภาษาหนึ่งเป็นอีกภาษาหนึ่งไม่เพียงเกี่ยวกับการเปลี่ยนแปลงซอร์สโค้ดเท่านั้น แต่ยังเกี่ยวกับสภาพแวดล้อมที่เราดำเนินโปรเจ็กต์นั้นด้วย CodePorting.Translator Java Class Library ใช้สภาพแวดล้อมดังกล่าวผ่าน JCL (ไลบรารีคลาส Java) โดยคงตรรกะและโครงสร้างของไลบรารีคลาส .NET Framework ไว้ ซึ่งทำให้โปรเจ็กต์ที่แปลแล้วรู้สึกเหมือนอยู่บ้าน โดยซ่อนตัวจากการนำแพลตฟอร์ม Java ไปใช้

CodePorting.Translator Java Class Library

JCL (ไลบรารีคลาส Java) แตกต่างจากไลบรารีคลาส .NET ในการออกแบบทั่วไป การจัดการข้อยกเว้น และตรรกะ ดังนั้น หากเราตัดสินใจแปลโค้ดของเราจาก C# เป็น Java แค่เปลี่ยนชื่อคลาสและฟังก์ชันก็จะไม่ปลอดภัยแล้ว อาจมีวิธีแก้ไขในการสร้างโค้ดการห่อซึ่งจะสร้างตรรกะไลบรารีคลาส .NET Framework ขึ้นมาใหม่ แต่วิธีนี้จะทำให้โค้ด Java ที่ได้ออกมาจะแตกต่างอย่างมากจากโค้ด C# ต้นฉบับ ซึ่งไม่ใช่สิ่งที่เราคาดหวังไว้ – เราต้องการให้นักแปล คงโครงสร้างโปรแกรมดั้งเดิมไว้ ที่นี่เรากำลังมาถึงความจำเป็นในการใช้การแทนที่ Java ของไลบรารีคลาสเฟรมเวิร์ก .NET

มันทำงานอย่างไร

เรามาเริ่มด้วยสิ่งที่ง่ายๆ:

using System;

class Program
{
    public static void Main(string[] args)
    {
        Console.WriteLine("Hello, Example!");
    }
}

เรามีคลาสจากไลบรารีคลาส .NET Framework – System.Console
โค้ด Java ที่แปลแล้วจะดูเป็นอย่างไร

import com.codeporting.ms.System.Console;

class Program
{
    public static void main(String[] args)
    {
        Console.writeLine("Hello, Example!");
    }
}

ดังที่คุณเห็น นักแปลจะแทนที่การอ้างอิงจากคลาส System.Console ของ C# ไปเป็นคลาส Java com.codeporting.ms.System.Console ซึ่งนำไปใช้ใน CodePorting.Translator Java Class Library

ทีนี้เรามาดูอีกตัวอย่างหนึ่ง:

using System;
using System.Collections.Generic;

class Program
{
    public static void Main(string[] args)
    {
        PrintList(new List<string> { "Hello, list!", "I have a list for you to print!" });
    }
    public static void PrintList(List<string> list)
    {
        foreach(var item in list) Console.WriteLine(item);
    }
}

โค้ด Java ที่แปลจะเป็นดังนี้:

import com.codeporting.ms.System.Collections.Generic.IGenericEnumerable;
import com.codeporting.ms.System.Collections.Generic.List;
import com.codeporting.ms.System.Console;
import com.codeporting.ms.System.IDisposable;
import java.util.Iterator;

class Program
{
    public static void main(String[] args)
    {
        List<String> tmp = new List<String>();
        tmp.addItem("Hello, list!");
        tmp.addItem("I have a list for you to print!");
        printList(tmp);
    }
    public static void printList(IGenericEnumerable<String> list)
    {
        //Foreach to while statement conversion
        Iterator<String> variable1 = list.iterator();
        try
        {
            while (variable1.hasNext())
            {
                String item = variable1.next();
                Console.writeLine(item);
            }
        }
        finally
        {
            if (variable1 != null)
            {
                ((IDisposable)variable1).dispose();
            }
        }
    }
}

ที่นี่เราเห็นข้อดีอีกอย่างหนึ่งจากการใช้ CodePorting.Translator Java Class Library – เรารักษาความสัมพันธ์ระหว่างนามธรรมของ C# System.Collections.Generic.List ใช้อินเทอร์เฟซ IEnumerable ซึ่งทำให้เราสามารถวนซ้ำผ่านอินเทอร์เฟซ foreach Java มีอินเทอร์เฟซ java.lang.Iterable และมันดูคล้ายกับ IEnumerable แต่มีความแตกต่างเล็กน้อยในการออกแบบ ซึ่งอาจกลายเป็นการตัดสินใจสำหรับโปรเจ็กต์ขนาดใหญ่

ความบริสุทธิ์ของ API สาธารณะ

แม้ว่าเราจะมีไลบรารีที่ดีให้ใช้ แต่โปรเจ็กต์ที่เราแปลจำเป็นต้องเข้าถึงและเข้าใจได้โดยลูกค้า และพวกเขาอาจต้องการใช้คลาส JCL คงจะดีถ้าซ่อนตัวจากโลกภายนอกที่เราใช้ CodePorting.Translator Java Class Library และที่นี่ เรามีฟีเจอร์ CodePorting.Translator ที่น่าสนใจอีกอย่างหนึ่ง: ApiChange คุณสมบัตินี้ทำอะไร? มันจะซ่อนวิธีการที่ใช้ CodePorting.Translator Java Class Library โดยสร้างวิธีการพร็อกซีที่ใช้คลาส JCL ให้เราดูตัวอย่าง:

using System;
using System.Collections.Generic;
using System.Linq;

namespace Newspaper
{
    public class Article
    {
        public DateTime Published { get; set; }
        public string Content { get; set; }
    }

    public class Archive
    {
        List<Article> articles = new List<Article>();

        public void AddArticle(Article article)
        {
            articles.Add(article);
        }

        public IEnumerable<Article> GetArticlesForPeriod(DateTime start, DateTime end)
        {
            if(start > end || start > DateTime.Now)
            {
                return new Article[0];
            }
            return articles.Where(article => article.Published >= start && article.Published <= end);
        }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            var archive = new Archive();
            archive.AddArticle(
                new Article() {
                    Published = new DateTime(2012, 12, 20), Content = "End of the world comes tomorrow!" });
            archive.AddArticle(
                new Article() {
                    Published = new DateTime(2012, 12, 22), Content = "It was a huge joke..." });
            var articles = archive.GetArticlesForPeriod(
                new DateTime(2000, 1, 1),
                new DateTime(2012, 12, 21));
            foreach(var article in articles)
            {
                Console.WriteLine(article.Content);
            }
        }
    }
}

คุณอาจเห็นคลาสง่ายๆ Archive ที่นี่ซึ่งจัดเก็บบทความบางบทความและให้สิทธิ์เข้าถึงบทความเหล่านั้น โดยใช้ตัวกรองตามวันที่เผยแพร่บทความ คลาส System.DateTime เป็นส่วนหนึ่งของ ไลบรารีคลาส .NET Framework และแม้ว่าเราอาจใช้ในโครงการของเรา แต่เราต้องการที่จะซ่อนมันจากโลกภายนอก:

Article.java

package Newspaper;

import com.codeporting.ms.System.DateTime;
import java.util.Date;

public class Article
{
    private DateTime auto_Published = new DateTime();
    final DateTime getPublishedInternal() { return auto_Published.Clone(); }
    public final Date getPublished() {
        return DateTime.toJava(getPublishedInternal());
    }
    final void setPublishedInternal(DateTime value) { auto_Published = value.Clone(); }
    public final void setPublished(Date value) {
        setPublishedInternal(DateTime.fromJava(value));
    }
    private String auto_Content;
    public final String getContent() { return auto_Content; }
    public final void setContent(String value) { auto_Content = value; }
}

Archive.java

package Newspaper;

import com.codeporting.ms.System.Collections.Generic.IGenericEnumerable;
import com.codeporting.ms.System.Collections.Generic.List;
import com.codeporting.ms.System.DateTime;
import com.codeporting.ms.System.Func;
import java.util.Date;

public class Archive
{
    private Archive[] Archive_this = {this};
    private List<Article> articles = new List<Article>();

    public final void addArticle(Article article)
    {
        articles.addItem(article);
    }

    final IGenericEnumerable<Article> getArticlesForPeriodInternal(DateTime start, DateTime end)
    {
        if(DateTime.op_GreaterThan(start, end) || DateTime.op_GreaterThan(start, DateTime.getNow()))
        {
            return com.codeporting.ms.System.Array.<Article>toGenericList(new Article[0]);
        }
        return articles.where(new Func<Article,Boolean>() {
            public String getDelegateId() {
                return System.identityHashCode(Archive_this[0]) + "-89480671";
            }
            public Boolean invoke(Newspaper.Article article) {
                return DateTime.op_GreaterThanOrEqual(article.getPublishedInternal(), start) 
                    && DateTime.op_LessThanOrEqual(article.getPublishedInternal(), end);
            }
        });
    }

    public final java.lang.Iterable<Article> getArticlesForPeriod(Date start, Date end)
    {
        IGenericEnumerable<Article> temp=getArticlesForPeriodInternal(
            DateTime.fromJava(start),
            DateTime.fromJava(end));
        java.util.ArrayList<Article> temp_java=new java.util.ArrayList<Article>();
        {
            com.codeporting.ms.System.Collections.Generic.IGenericEnumerator<Article> temp_iterator=temp.iterator();
            while(temp_iterator.hasNext())
            {
                Article element=temp_iterator.next();
                temp_java.add(element);
            }
        }
        return temp_java;
    }
}

Program.java

package Newspaper;

import com.codeporting.ms.System.Collections.Generic.IGenericEnumerable;
import com.codeporting.ms.System.Console;
import com.codeporting.ms.System.DateTime;
import com.codeporting.ms.System.IDisposable;
import java.util.Iterator;

public class Program
{
    public static void main(String[] args)
    {
        Archive archive = new Archive();
        Article tmp = new Article();
        tmp.setPublishedInternal(new DateTime(2012, 12, 20));
        tmp.setContent("End of the world comes tomorrow!" ) ;
        archive.addArticle(tmp);
        Article tmp_1 = new Article();
        tmp_1.setPublishedInternal(new DateTime(2012, 12, 22));
        tmp_1.setContent("It was a huge joke..." ) ;
        archive.addArticle(tmp_1);
        IGenericEnumerable<Article> articles = archive.getArticlesForPeriodInternal(
	        new DateTime(2000, 1, 1),
	        new DateTime(2012, 12, 21));
        //Foreach to while statement conversion
        Iterator<Article> variable1 = articles.iterator();
        try
        {
            while (variable1.hasNext())
            {
                Article article = variable1.next();
                Console.writeLine(article.getContent());
            }
        }
        finally
        {
            if (variable1 != null)
            {
                ((IDisposable)variable1).dispose();
            }
        }
    }
}

โค้ดที่แปลเป็น Java ไม่มีการเข้าถึง CodePorting.Translator Java Class Library ผ่านทาง API สาธารณะ และโลก Java ภายนอกอาจโต้ตอบกับคลาส Archive ของเรา โดยใช้วิธีพร็อกซีสาธารณะ

สิ่งที่เราสรุป

CodePorting.Translator Java Class Library มีเลเยอร์นามธรรมและการควบคุม JCL ซึ่งทำให้เราไม่ใส่ใจรายละเอียดการใช้งาน และช่วยให้เราคิดถึงปัญหาที่เราแก้ไขได้
นอกจากนี้ยังช่วยรักษาโครงสร้างของโค้ดต้นฉบับเพิ่มความเข้าใจและความโปร่งใสของผลการแปล

บทความที่เกี่ยวข้อง