28 февраля 2024
Перевод некоторых проектов с одного языка на другой связан не только с изменением исходного кода, но и окружения, в котором будет выполняеться проект. CodePorting.Translator Java Class Library реализует такое окружение через JCL (библиотеку классов Java), сохраняя логику и структуру библиотеки классов .NET Framework. Это обеспечивает переведенному проекту идентичную среду выполнения и скрывает его от реализации платформы Java.
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
, но у них есть небольшие различия в дизайне, которые могут стать решающими для большого проекта.
Хотя у нас есть хорошая библиотека, которую можно использовать, проект, который мы переводим, должен быть доступен и понятен клиентам, а они могут предпочесть использовать классы 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, что скрывает от нас детали реализации и позволяет сосредоточиться на проблемах, которые мы решаем. Это также помогает сохранить структуру оригинального кода, повышая понятность и прозрачность результата трансляции.