Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Introduction
I wanted to take some code and make it more general purpose
C# generics didn’t quite cut it.
I wanted a generic routine that could save objects with different properties
But I didn’t want ugly, “hard to comprehend in 3 months from now” code
The traditional approach is to use Interfaces to guarantee that templated objects support the same methods
But I wanted to make objects generic that had different properties (An impossibility as far as I could tell)
If you want to support objects that have different properties, I couldn’t find an elegant way to do it
- See lines 42 to 45 of part 2 of the code
- T2 needs to have a property called FolderName and Folder
- So unless my template objects have the same properties, I am out of luck
- I can see why the compiler could complain
- But I am will to sacrifice compile time safety in favor of code re-use
The code speaks for itself so there is barely any narrative here
I present the before and after
I’m sure many of you will find a better way and I look forward to seeing the comments
There is use of delegates so that even a function call can be abstracted out of the code
Some of code can be found here for serialization
The code can serialize and save a collection of objects
The collection is composed of string paths to folders (I couldn’t save the StorageFolder object by itself)
Non-Generic Version
This the "before" version.
It makes NO USE OF GENERICS
Non-Generics Version | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | ////////////////////////////////////////////////////////////////////// // // Non-generic code // // async private void SaveSearch_Click(object sender, RoutedEventArgs e) { await SaveToDisk(); } async private void OpenSearch_Click(object sender, RoutedEventArgs e) { await ReadFromFile(); } private static async Task SaveToDisk() { // Creat a save-able object list List<FoldersItemDisk> dataToSave = new List<FoldersItemDisk>(); foreach (FoldersItem item in MyGlobals.itemsFoldersItems) { dataToSave.Add(new FoldersItemDisk { FolderName = item.FolderName }); } // Make xml out of it string localData = ObjectSerializer<List<FoldersItemDisk>>.ToXml(dataToSave); // Save to disk part 1 StorageFolder storageFolder = ApplicationData.Current.LocalFolder; StorageFile storageFile = await storageFolder.CreateFileAsync("Results1.dat", CreationCollisionOption.ReplaceExisting); // Save to disk part 2 using (IRandomAccessStream stream = await storageFile.OpenAsync(FileAccessMode.ReadWrite)) { using (DataWriter dataWriter = new DataWriter(stream)) { dataWriter.WriteString(localData); await dataWriter.StoreAsync(); } } } private async Task ReadFromFile() { try { StorageFolder storageFolder = ApplicationData.Current.LocalFolder; StorageFile storageFile = await storageFolder.GetFileAsync("Results1.dat"); using (IRandomAccessStreamWithContentType readStream = await storageFile.OpenReadAsync()) using (DataReader reader = new DataReader(readStream)) { ulong streamSize = readStream.Size; UInt32 totalBytesRead = await reader.LoadAsync((UInt32)streamSize); string s = reader.ReadString(totalBytesRead); List<FoldersItemDisk> localData = ObjectSerializer<List<FoldersItemDisk>>.FromXml(s); section1FolderSelection.AssignCollectionToDataSource(); } } catch (FileNotFoundException) { } } |
Improved Generic Version
This the "after" version.
It makes USE OF GENERICS
Generics Version | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | ////////////////////////////////////////////////////////////////////// // // Generic code // // public delegate void ResetCollectionWithSource(); async private void SaveSearch_Click(object sender, RoutedEventArgs e) { await SaveToDisk<FoldersItemDisk, FoldersItem>(MyGlobals.itemsFoldersItems, "SavedFolders.dat"); } async private void OpenSearch_Click(object sender, RoutedEventArgs e) { ResetCollectionWithSource resetCollectionWithSource = section1FolderSelection.AssignCollectionToDataSource; await ReadFromFile<FoldersItemDisk, FoldersItem>(MyGlobals.itemsFoldersItems, resetCollectionWithSource, "SavedFolders.dat"); } private async Task ReadFromFile<T, T2>(ObservableCollection<T2> collection, ResetCollectionWithSource myfunc, string filename) where T : FoldersItemDisk, new() where T2 : FoldersItem, new() { try { StorageFolder storageFolder = ApplicationData.Current.LocalFolder; StorageFile storageFile = await storageFolder.GetFileAsync(filename); using (IRandomAccessStreamWithContentType readStream = await storageFile.OpenReadAsync()) using (DataReader reader = new DataReader(readStream)) { ulong streamSize = readStream.Size; UInt32 totalBytesRead = await reader.LoadAsync((UInt32)streamSize); string s = reader.ReadString(totalBytesRead); List<T> localData = ObjectSerializer<List<T>>.FromXml(s); MyGlobals.itemsFoldersItems.Clear(); foreach (T item in localData) { collection.Add(new T2 { FolderName = item.FolderName, Folder = await StorageFolder.GetFolderFromPathAsync(item.FolderName) }); } myfunc(); } } catch (FileNotFoundException) { } } |
Comments
Anonymous
July 14, 2014
Why does type T2 have to have those 2 properties. Try this: foreach (T item in localData) { collection.Add(new T2()); }Anonymous
July 14, 2014
...or replace item.FolderName with System.IO.Path.GetDirectoryName(fileName)Anonymous
July 14, 2014
It's 2014... Stop using XML. > ToXml Just serialize it to JSON. @QuintonnBecause it just does. The point of the collection is to save it and I am using generics to save different object types. I just can't get around the fact that each object type has different properties. There is a way that is elegant somewhere in my brain but just can't get to it yet.@PhillipGood guidance. XML is wasteful and not that much more readable. The XML serializer/deserializer just worked so I kept it. I will look for a JSON version.Anonymous
July 15, 2014
JSON vs XML1
2
3
4
5
6
7 string json = JsonConvert.SerializeObject(dataToSave, new JsonSerializerSettings
{
Formatting = Formatting.Indented,
});
// Make xml out of it
string localData = ObjectSerializer<List<FoldersItemDisk>>.ToXml(dataToSave);