C#에서 Java로 변환 – Java 환경에서 .NET Framework 논리 사용

일부 프로젝트를 한 언어에서 다른 언어로 번역할 때는 소스 코드의 변경뿐만 아니라 프로젝트를 실행하는 환경도 중요합니다. CodePorting.Translator Java Class Library는 이러한 환경을 JCL(Java 클래스 라이브러리)을 통해 구현하여 .NET Framework 클래스 라이브러리의 로직과 구조를 유지함으로써 번역된 프로젝트가 Java 플랫폼 구현에서 숨겨져 있는 것처럼 느껴지도록 합니다.

CodePorting.Translator Java Class Library

JCL(Java 클래스 라이브러리)은 일반적인 디자인, 예외 처리 및 로직에서 .NET 클래스 라이브러리와 다릅니다. 따라서 코드를 C#에서 Java로 변환하기로 결정한 경우 클래스와 함수의 이름만 바꾸는 것은 안전하지 않을 수 있습니다. 래핑 코드를 생성하여 .NET Framework 클래스 라이브러리 로직을 재현하는 솔루션이 있을 수 있습니다. 하지만 이렇게 하면 결과 Java 코드가 원래 C# 코드와 크게 달라지므로, 번역기가 원래 프로그램 구조를유지 하기를 바라는 우리의 기대와는 맞지 않습니다. 여기서 우리는 .NET 프레임워크 클래스 라이브러리의 Java 대체를 구현해야 할 필요성에 도달하게 됩니다.

작동 방식

간단한 것부터 시작하겠습니다:

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!");
    }
}

보시다시피, 번역기는 참조를 C# System.Console 클래스에서 CodePorting.Translator Java Class Library에 구현된 Java com.codeporting.ms.System.Console 클래스로 대체합니다.

이제 다른 예를 살펴보겠습니다:

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.ListIEnumerable 인터페이스를 구현하므로 foreach 루프를 사용하여 이를 반복할 수 있습니다. Java에는 java.lang.Iterable 인터페이스가 있으며, IEnumerable과 비슷해 보이지만 설계에 약간의 차이가 있어 대규모 프로젝트에서 결정적인 차이가 될 수 있습니다.

퍼블릭 API 순도

사용할 수 있는 좋은 라이브러리가 있더라도 번역하는 프로젝트는 고객이 액세스하고 이해할 수 있어야 하며, 고객은 JCL 클래스를 사용하는 것을 선호할 수 있습니다. 외부에서 CodePorting.Translator Java Class Library를 사용한다는 사실을 숨기는 것이 좋을 것입니다. 그리고 여기 또 다른 흥미로운 CodePorting.Translator 기능이 있습니다: ApiChange. 이 기능은 무엇을 할까요? CodePorting.Translator 자바 클래스 라이브러리를 사용하는 메서드를 숨기고, 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 코드로 번역된 경우 공개 API를 통해 CodePorting.Translator Java Class Library에 액세스할 수 없으며, 외부 Java 세계에서는 공용 프록시 메서드를 사용하여 Archive 클래스와 상호 작용할 수 있습니다.

결론을 내릴 수 있는 내용

CodePorting.Translator Java Class Library는 추상화 계층과 JCL에 대한 제어 기능을 제공하므로 구현 세부 사항에서 벗어나 해결해야 할 문제에 대해 생각할 수 있습니다.
또한 원본 코드의 구조를 유지하여 번역 결과의 이해도와 투명성을 높이는 데 도움이 됩니다.

관련 기사