28 Februar 2024
Die Übersetzung von Projekten von einer Sprache in eine andere betrifft nicht nur Änderungen im Quellcode, sondern auch die Umgebung, in der wir dieses Projekt ausführen. Die CodePorting.Translator Java Class Library implementiert eine solche Umgebung über die JCL (Java-Klassenbibliothek), wobei die Logik und Struktur der .NET Framework-Klassenbibliothek beibehalten werden. Dadurch fühlt sich ein übersetztes Projekt wie zu Hause an und bleibt vor der Java-Plattformimplementierung verborgen.
Die JCL (Java-Klassenbibliothek) unterscheidet sich im allgemeinen Design, bei der Behandlung von Ausnahmen und in der Logik von der .NET-Klassenbibliothek. Wenn wir uns also entscheiden, unseren Code von C# nach Java zu übersetzen, wäre es unsicher, einfach die Namen von Klassen und Funktionen zu ersetzen. Es könnte eine Lösung geben, um Wrapper-Code zu generieren, der die Logik der .NET Framework-Klassenbibliothek reproduziert. Auf diese Weise würde der resultierende Java-Code jedoch erheblich vom ursprünglichen C#-Code abweichen, was nicht unseren Erwartungen entspricht – wir möchten, dass ein Übersetzer die ursprüngliche Programmstruktur beibehält. Hier kommen wir zur Notwendigkeit, eine Java-Version der .NET Framework-Klassenbibliothek zu implementieren.
Beginnen wir mit etwas Einfachem:
using System;
class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Hello, Example!");
}
}
Wir haben hier eine Klasse aus der .NET Framework-Klassenbibliothek –- System.Console
.
Wie würde der übersetzte Java-Code aussehen?
import com.codeporting.ms.System.Console;
class Program
{
public static void main(String[] args)
{
Console.writeLine("Hello, Example!");
}
}
Wie Sie sehen können, ersetzt der Übersetzer die Referenz von der C#-Klasse System.Console
durch die Java-Klasse com.codeporting.ms.System.Console
, die in der CodePorting.Translator Java Class Library implementiert ist.
Nun schauen wir uns ein weiteres Beispiel an:
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);
}
}
Der übersetzte Java-Code wäre folgender:
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();
}
}
}
}
Hier sehen wir einen weiteren Vorteil der Verwendung der CodePorting.Translator Java Class Library: Wir behalten die Beziehungen zwischen C#-Abstraktionen bei. System.Collections.Generic.List
implementiert das IEnumerable
-Interface, was es uns ermöglicht, es mit einer foreach
-Schleife zu durchlaufen. Java verfügt über das java.lang.Iterable
-Interface, das dem IEnumerable
-Interface ähnlich aussieht, aber kleine Unterschiede im Design aufweist, die für ein großes Projekt entscheidend sein können.
Obwohl wir eine schöne Bibliothek verwenden, muss ein übersetztes Projekt für Kunden zugänglich und verständlich sein, und sie bevorzugen möglicherweise die Verwendung von JCL-Klassen. Es wäre gut, vor der Außenwelt zu verbergen, dass wir die CodePorting.Translator Java Class Library verwenden. Und hier haben wir ein weiteres interessantes Feature des CodePorting.Translator: ApiChange. Was macht dieses Feature? Es verbirgt Methoden, die die CodePorting.Translator Java Class Library verwenden, und erstellt Proxy-Methoden, die JCL-Klassen verwenden. Schauen wir uns das Beispiel an:
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);
}
}
}
}
Hier sehen Sie eine einfache Klasse Archive
, die einige Artikel speichert und den Zugriff auf sie ermöglicht, indem ein Filter nach dem Veröffentlichungsdatum des Artikels angewendet wird.
Die Klasse System.DateTime
ist Teil der .NET Framework-Klassenbibliothek, und obwohl wir sie in unserem Projekt verwenden können, möchten wir sie vor der Außenwelt verbergen:
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();
}
}
}
}
Der übersetzte Java-Code gewährt keinen Zugriff auf die CodePorting.Translator Java Class Library über die öffentliche API, und die äußere Java-Welt kann mit unserer Archive
-Klasse über öffentliche Proxy-Methoden interagieren.
Die CodePorting.Translator Java Class Library bietet eine Abstraktionsebene und Kontrolle über JCL, die uns von Implementierungsdetails ablenkt und es uns ermöglicht, über die Probleme nachzudenken, die wir lösen.
Sie hilft auch dabei, die Struktur des ursprünglichen Codes beizubehalten und die Verständlichkeit und Transparenz des Übersetzungsergebnisses zu erhöhen.