Serializer gesucht

BAGZZlash

Moderator
Teammitglied
Ich erzeuge in C# eine Klasse, die einige Felder hat, die in den Geo-Informatik-Paketen GDAL bzw. OGR (NuGet) definiert sind, nämlich "DataSource" und "Layer". Ich möchte nun eine Instanz dieser Klasse serialisieren. Ich habe es schon mit einigen Serialisierern probiert (JSON, XmlSerializer, BinaryFormatter, System.Runtime.Serialization und DataContractSerializer). Ich komme aber nicht weiter, weil die GDAL- bzw. OGR-Klassen entweder nicht als [Serializable] markiert sind oder keinen parameterless constructor verwenden. Meine eigenen Felder kann ich ja soweit zurechtklöppeln, aber an die Klassen aus den Packages komme ich entweder gar nicht dran, oder ich mache mir damit die Kompatibilität nach außen hin kaputt.

Hat da jemand nen heißen Tipp? Hier mal ein Minimalbeispiel:

C#:
// clang-format off
using OSGeo.GDAL;
using OSGeo.OGR;

using System.IO;
using System.Runtime.Serialization;

namespace MyProj
{
    public class Shapefile
    {
        public string sFilename;
        public int firstLayer = 0;
        public Boolean Loaded = false;
        public DataSource ds;
        public Layer Layer;

        // Irgendwelcher Mist
    }

public class Program
{
    static async Task Main(string[] args)
    {
        Shapefile TestShapeFile = new Shapefile();
        TestShapeFile.sFilename = "C:/Temp/MyShape.shp";
        Boolean LoadSuccess = TestShapeFile.LoadShapeFile(TestShapeFile.sFilename);

        Console.WriteLine("Shapefile loaded successfully: {0}", LoadSuccess);

        DataContractSerializer ser = new DataContractSerializer(typeof(Shapefile))
        FileStream writer = new FileStream("C:/Temp/Test.dta", FileMode.Create);
        ser.WriteObject(writer, TestShapeFile);

        //...

/edit: Irgendwie wird der Code automatisch so komisch formatiert. Kann man das irgendwie verhindern?
 
Zuletzt bearbeitet:

BAGZZlash

Moderator
Teammitglied
Falls das so niemand direkt beantworten kann, frage ich mal anders: Angenommen, ich verwende eine Klasse, deren Code ich nicht ändern kann/darf. Die Klasse hat keinen parameterlosen Konstruktor. Gibt es dann eine Möglichkeit, nachträglich, also sozusagen von "außen", einen parameterlosen Konstruktor hinzuzufügen/zu überladen?
 

german

Aktives Mitglied
devCommunity-Experte
Ich mach nix mit C#, aber ist Vererbung nicht eine Möglichkeit?
C#:
public
class MyExtendedShapefile : Shapefile {
  // ...
}
 

BAGZZlash

Moderator
Teammitglied
Vielen Dank. Ja, das hatte ich in der Tat schon versucht. Die Klasse, von der ich da erben will (DataSource) hat nur einen Konstruktor, und der erwartet drei Parameter. Schreibe ich eine Kind-Klasse, die von DataSource erbt (z.B. "DataSourceChild"), kann ich keinen parameterlosen Konstruktor für DataSourceChild schreiben, oder? Oder weiß da jemand nen Trick?
 

lord_haffi

Moderator
Teammitglied
Von C# habe ich zwar keine Ahnung, aber normalerweise müsstest du für die Kindklasse einen parameterlosen Konstruktor definieren können, wenn du dann den Superkonstruktor mit den 3 Parametern darin aufrufst. Du kannst alternativ auch eine statische Funktion ohne Parameter implementieren, die das Objekt dann für dich instanziiert (mit den 3 Parametern) und zurückgibt. Dann musst du keine komplette Kindklasse definieren.
Mich würde es allerdings wundern, wenn du es dadurch schaffst, das Ding zu serialisieren ^^
 
Zuletzt bearbeitet:

BAGZZlash

Moderator
Teammitglied
Von C# habe ich zwar keine Ahnung, aber normalerweise müsstest du für die Kindklasse einen parameterlosen Konstruktor definieren können, wenn du dann den Superkonstruktor mit den 3 Parametern darin aufrufst. Du kannst alternativ auch eine statische Funktion ohne Parameter implementieren, die das Objekt dann für dich instanziiert (mit den 3 Parametern) und zurückgibt. Dann musst du keine komplette Kindklasse definieren.
Okay, dann probiere ich mal noch ein bisschen rum. Bin auch ziemlich neu in C#.

Mich würde es allerdings wundern, wenn du es dadurch schaffst, das Ding zu serialisieren ^^
Mich tatsächlich auch. Falls kein Wunder geschieht, bin ich wieder zurück auf Feld eins. Was mach' ich nu?
 

Rushh0ur

Neues Mitglied
Du kannst es schon quasi vergessen die Datenklassen aus dem GDAL/OGR Package zu serialisieren.
Alles was da bereitgestellt wird sind Wrapper Klassen zu Unmanaged C/++ Bibliotheken, die im Prinzip nur Funktionsaufrufe bereitstellen; die kann man nicht einfach so mit irgendwelchen Konstruktorargumenten füttern.
Die ganzen Standard C# Serializer brauchen Klassen mit Properties, die dazu noch teilweiße mit entsprechenden Attributen versehen sein müssen.

Ich habe mit dem Zeug keine Berührungspunkte aber offensichtlich werden bereits diverse Funktionen bereitgestellt zum Serializieren.
So hat die Geometry Klasse eine ExportToJson Funktion. Die OpenEx Funktion soll auch JSON als Input annehmen können.

Je nach dem was du genau vor hast muss man etwas Hand anlegen. Zum Beispiel mit einer eigenen Extension Methode und hier mit Hilfe des Newtonsoft.Josn Nuget Packages:

C#:
// clang-format off

using Newtonsoft.Json.Linq;
using OSGeo.OGR;
using System;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            GdalConfiguration.ConfigureGdal();
            GdalConfiguration.ConfigureOgr();

            using (var dataSource = Ogr.Open("gis_osm_boundaries_07_1.shp", 0))
            {
                var json = dataSource.SerializeToJson();
                Console.WriteLine(json);
            }

            Console.ReadLine();
        }
    }

    static class DataSourceExtensions
    {
        public static string SerializeToJson(this DataSource self)
        {
            var jsonRoot = new JObject();

            var name = self.GetName();
            jsonRoot.Add("Name", name);
            Console.WriteLine("Name: {0}", name);

            var layerCount = self.GetLayerCount();
            jsonRoot.Add("LayerCount", layerCount);
            Console.WriteLine("LayerCount: {0}", layerCount);

            var jsonLayerList = new JObject();
            for (int layerIndex = 0; layerIndex < layerCount; ++layerIndex)
            {
                using (var layer = self.GetLayerByIndex(layerIndex))
                {
                    var jsonLayer = new JObject();

                    var featureCount = layer.GetFeatureCount(0);
                    jsonLayer.Add("FeatureCount", featureCount);
                    Console.WriteLine("FeatureCount: {0} in Layer {1}", featureCount, layerIndex);

                    var jsonFeatureList = new JObject();
                    for (int featureIndex = 0; featureIndex < featureCount; ++featureIndex)
                    {
                        using (var feature = layer.GetFeature(featureIndex))
                        {
                            using (var geo = feature.GetGeometryRef())
                            {
                                var options = new string[] { };
                                var json = geo.ExportToJson(options);
                                var jsonFeature = JObject.Parse(json);

                                jsonFeatureList.Add($"{featureIndex}", jsonFeature);
                              
                            }
                        }
                    }
                    jsonLayer.Add("Features", jsonFeatureList);

                    jsonLayerList.Add($"{layerIndex}", jsonLayer);
                }
            }
            jsonRoot.Add("Layers", jsonLayerList);

            return jsonRoot.ToString();
        }
    }
}
 

BAGZZlash

Moderator
Teammitglied
Okay, nochmal vielen Dank. Bin erst jetzt dazu gekommen, das alles zurechtzubasteln, aber jetzt rennt's wie ne Eins. Super! :cool:
 
Oben Unten