Конвертация 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 Framework.

Как это работает

Начнем с простого примера:

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 на класс 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, создавая прокси-методы, использующие классы 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, что скрывает от нас детали реализации и позволяет сосредоточиться на проблемах, которые мы решаем. Это также помогает сохранить структуру оригинального кода, повышая понятность и прозрачность результата трансляции.

Связанные статьи