28 2月 2024

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 Framework クラス ライブラリの 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を使用していることを外の世界から隠すとよいでしょう。 そして、ここにはもう 1 つの興味深い CodePorting.Translator 機能、ApiChange があります。 この機能は何をするのでしょうか? CodePorting.Translator Java クラス ライブラリを使用するメソッドを非表示にし、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 の制御を提供します。これにより、実装の詳細から気をそらし、解決する問題について考えることができます。 また、元のコードの構造を維持するのにも役立ち、翻訳結果の理解力と透明性が向上します。

関連ニュース

関連記事