PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C#: Generische Methode programmieren, wie?


mf_2
2011-03-06, 15:31:57
Hallo zusammen,

ich wollte mich ein wenig in db4o unter C# einarbeiten und möchte nun zur Speicherung von Objketen eine generische Methode verwenden.
Beispielsweise habe ich die Klassen "Auto" und "LKW", welche beide von der Oberklasse "Fahrzeug" erben.
Nun habe ich einen Datenbank-Manager (FahrzeugManager) geschrieben, welcher folgende Methode enthält um die Objekte zu speichern:

public List<Fahrzeug> GetAllSortedBy(string key, OrderBy sortingOrder)
{
using (IObjectContainer db = Db4oEmbedded.OpenFile(this.GetTableName() + ".db4o"))
{
IObjectSet result = null;
IQuery query = db.Query();
query.Constrain(typeof(object));
if(sortingOrder == OrderBy.Ascending)
{
result = query.Descend(key).OrderAscending().Execute();
}
if (sortingOrder == OrderBy.Descending)
{
result = query.Descend(key).OrderDescending().Execute();
}
List<Fahrzeug> liste = new List<Fahrzeug>();
foreach (object item in result)
{
liste.Add((Fahrzeug)item);
}
return liste;
}
}

AutoManager und LKWManager leiten davon ab und unterscheiden sich in diesem Minimal-Beispiel nur in der Rückgabe der GetTableName() Methode.

Diese GetAllSortedBy()-Methode soll nun sortiert alle Autos oder LKws zurück geben.
Ich möchte nun vermeiden, die Methode jeweils einmal für die Auto-Klasse und die Fahrzeug-Klasse schreiben zu müssen, da diese Methoden das gleiche machen würden.
Wenn ich "query.Constrain(typeof(object));" so lasse funktioniert die Sortierung nicht. Wenn ich "object" durch "Fahrzeug" oder auch durch "Auto" ersetze werden keine Objekte gefunden.
Wenn ich aber mit der Einstellung "object" das "result" Objektset ansehe, dann liegen da "Auto"s drin, es sollte also gehen.

Was mache ich falsch?

EDIT: Sorry, hab zuerst die falsche Klassenmethode im Verdacht gehabt, Post ist editiert.

Monger
2011-03-06, 16:18:02
Ich hab mal gesucht, ob ich die db4o API Doku irgendwo finden kann, hatte aber keinen Erfolg...

Die Frage hat mMn erstmal wenig mit Generics zu tun. Die Frage ist, was genau dieses "Query.Constrain(...)" macht... und das lässt sich nunmal nur klären, wenn man in die Dokumentation reinschaut.

So rein formal sieht das für mich richtig aus was du da tust.

mf_2
2011-03-06, 17:15:54
Ich habe via google Books ein Buch dazu gefunden. Hier geht es um die Sortierung:
http://books.google.de/books?id=SXG19zl8qF4C&lpg=PA376&ots=w7ARrUD7Ti&dq=db4o%20%22order%20by%22%20c%23&pg=PA124#v=onepage&q=order%20by&f=false

Hier geht es speziell um Constrain():
https://developer.db4o.com/Documentation/Reference/db4o-5.4/mono/api/com.db4o.query.Query.Constrain.html

Da heißt es in den Anmerkungen:

Special behaviour for:

* class Class : confine the result to objects of one class or to objects implementing an interface.


Das heißt für mich sol viel, dass nur Objekte des per Parameter angegebenen Types zurückgeliefert werden sollen.

Im Buch stand auch, dass man alternativ eine neue Instanz des Objektes angeben kann bei Constrain().
Aber die Zeile in "query.Constrain(new Auto());" zu ändern brachte ebenfalls keinen Erfolg.

Edit: Ich habe gerade mal die Funktion ohne das Order... Zeug gestestet, damit geht es. Komisch. Vllt. kennt der das zu sortierende Attribut nicht. Es ist aber public.

Gnafoo
2011-03-06, 19:42:06
Ist nur eine Vermutung, aber probiere mal statt:


result = query.Descend(key).OrderAscending().Execute();


Das hier:


query.Descend(key).OrderAscending();
result = query.Execute();


Wenn ich das richtig verstehe, liefert dir Descend ja einen neuen Query-Knoten für das gegebene Attribut. An den klebst du die Sortierrichtung. Die Abfrage willst du jetzt aber nicht an diesen Query-Knoten richten, sondern an den Wurzelknoten „query“, an dem noch deine Typ-Einschränkung klebt. Schließlich willst du die auch berücksichtigen.

Vielleicht liege ich aber auch vollkommen falsch. Ich habe mir das eben nur aus der Doku zusammengedichtet.


„query“ (Attribute: type=…)
|
+-- „key“ (Attribute: order=…) <--- hier führst du atm. execute aus.

mf_2
2011-03-06, 23:39:15
Ich habe das nun geändert und bekomme folgende Exception:


System.Reflection.TargetInvocationException was unhandled
Message=Exception has been thrown by the target of an invocation.
Source=mscorlib
StackTrace:
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache)
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean skipCheckThis, Boolean fillCache)
at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
at System.Xaml.Schema.XamlTypeInvoker.CreateInstance(Object[] arguments)
at MS.Internal.Xaml.Runtime.ClrObjectRuntime.CreateInstanceWithCtor(XamlType xamlType, Object[] args)
at MS.Internal.Xaml.Runtime.ClrObjectRuntime.CreateInstance(XamlType xamlType, Object[] args)
at System.Xaml.XamlObjectWriter.Logic_CreateAndAssignToParentStart(ObjectWriterCont ext ctx)
at System.Xaml.XamlObjectWriter.WriteStartMember(XamlMember property)
at System.Xaml.XamlWriter.WriteNode(XamlReader reader)
at System.Windows.Markup.WpfXamlLoader.TransformNodes(XamlReader xamlReader, XamlObjectWriter xamlWriter, Boolean onlyLoadOneNode, Boolean skipJournaledProperties, Boolean shouldPassLineNumberInfo, IXamlLineInfo xamlLineInfo, IXamlLineInfoConsumer xamlLineInfoConsumer, XamlContextStack`1 stack, IStyleConnector styleConnector)
at System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
at System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader, Boolean skipJournaledProperties, Object rootObject, XamlAccessLevel accessLevel, Uri baseUri)
at System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream)
at System.Windows.Application.LoadBamlStreamWithSyncInfo(Stream stream, ParserContext pc)
at System.Windows.Application.LoadComponent(Uri resourceLocator, Boolean bSkipJournaledProperties)
at System.Windows.Application.DoStartup()
at System.Windows.Application.<.ctor>b__1(Object unused)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.DispatcherOperation.InvokeImpl()
at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
at System.Threading.ExecutionContext.runTryCode(Object userData)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup( TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Windows.Threading.DispatcherOperation.Invoke()
at System.Windows.Threading.Dispatcher.ProcessQueue()
at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.Run()
at System.Windows.Application.RunDispatcher(Object ignore)
at System.Windows.Application.RunInternal(Window window)
at System.Windows.Application.Run(Window window)
at System.Windows.Application.Run()
at Fahrzeug.App.Main() in C:\Users\mf_2\documents\visual studio 2010\Projects\Fahrzeug\Fahrzeug\obj\x86\Debug\App.g.cs:line 0
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException: System.NullReferenceException
Message=Object reference not set to an instance of an object.
Source=Db4objects.Db4o
StackTrace:
at Db4objects.Db4o.Internal.Query.SodaQueryComparator.ResolveFieldPath(String[] fieldPath)
at Db4objects.Db4o.Internal.Query.SodaQueryComparator.ResolveFieldPaths(Ordering[] orderings)
at Db4objects.Db4o.Internal.Query.SodaQueryComparator..ctor(LocalObjectContainer container, ClassMetadata extent, Ordering[] orderings)
at Db4objects.Db4o.Internal.Query.Processor.QQueryBase.NewSodaQueryComparator()
at Db4objects.Db4o.Internal.Query.Processor.QQueryBase.Sort(IQueryResult result)
at Db4objects.Db4o.Internal.Query.Processor.QQueryBase.ExecuteLocal(IdListQueryResu lt result)
at Db4objects.Db4o.Internal.Query.Result.IdListQueryResult.LoadFromQuery(QQuery query)
at Db4objects.Db4o.Internal.LocalObjectContainer.ExecuteQuery(QQuery query)
at Db4objects.Db4o.Internal.Query.Processor.QQueryBase.ExecuteQuery()
at Db4objects.Db4o.Internal.Query.Processor.QQueryBase.GetQueryResult()
at Db4objects.Db4o.Internal.Query.Processor.QQueryBase._IClosure4_331.Run()
at Db4objects.Db4o.Internal.Query.Processor.QQueryBase.TriggeringQueryEvents(IClosu re4 closure)
at Db4objects.Db4o.Internal.Query.Processor.QQueryBase.Execute()
at Fahrzeug.DbManager.GetAllSortedBy(String key, OrderBy sortingOrder) in C:\Users\mf_2\documents\visual studio 2010\Projects\Fahrzeug\Fahrzeug\DbManager.cs:line 105
at Fahrzeug.MainWindow..ctor() in C:\Users\mf_2\documents\visual studio 2010\Projects\Fahrzeug\Fahrzeug\MainWindow.xaml.cs:line 28
InnerException:


Da scheint es mit dem key Probleme zu geben. Der Key (sprich der Parameter für OrderDescending() lautet "name". Es gibt auch definitiv ein Feld mit dem Namen "name" in der Auto-Klasse (allerdings nicht in Fahrzeug).
So sieht der Code aus:


public List<Fahrzeug> GetAllSortedBy(string key, OrderBy sortingOrder)
{
using (IObjectContainer db = Db4oEmbedded.OpenFile(this.GetTableName() + ".db4o"))
{
IObjectSet result = null;
IQuery query = db.Query();
query.Constrain(typeof(Auto));
if (sortingOrder == OrderBy.Ascending)
{
query.Descend(key).OrderAscending();
}
if (sortingOrder == OrderBy.Descending)
{
query.Descend(key).OrderDescending();
}
result = query.Execute();
List<Fahrzeug> liste = new List<Fahrzeug>();
foreach (object item in result)
{
liste.Add((Fahrzeug)item);
}
return liste;
}
}

Was mache ich falsch? So wie ich die Doku verstehe soll ich den Namen des Feldes als string übergeben.
Das ist der Aufruf: grdFahrzeuge.ItemsSource = fzMgr.GetAllSortedBy("name",OrderBy.Descending);