Forcing a Class to have a .Parse Method - c#

TLDR Question:
How to cast a string to a specific type of object?
Long Question
I want to make a PlayerPrefs wrapper where I can store whatever data I want.
so it goes like this
void Set<T>(string Key, T Value)
{
PlayerPrefs.SetString(Key, Value.ToString());
}
T Get<T>(string Key)// where T : IParseable
{
//Code that checks for errors and throws exceptions
return T.Parse(PlayerPrefs.GetString(Key));
}
The problem in this is that it "relies" on the data to be parseable (or implement IParseable that I invented XD) and primitive data types don't implement it even thought they all have a Parse Method
Is there already an IParseable interface I can use?
If not, is there a way to know if the T type is a primitive data type?
Is there a better way to achieve what I want to do?
Would it be better if I used JSON for this?

The comments are correct, you shouldn't be using ToString() and Parse. What you are doing (or trying to do) is serialization. Here are a couple of resources to look to for figuring out how to serialize and deserialize your data:
Serialize an object to string
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-serialize-and-deserialize-json-data
If you use one of the above examples, the data should be serialized to a human-readable format. It's less efficient, but serializing to a string is already less efficient than serializing to bytes. If you need that level of efficiency, you shouldn't be using PlayerPrefs.

Related

C# - Using different types of object as function parameter

I´m writing a function which parses JSON and may return different types of objects.
Say, I´m parsing an bird json and want to return a bird object, then a tiger json and want to get a tiger object insted.
How can I do this? Should I use a dynamic object? And, if this is the answer, HOW?
I don´t want to overload the logic on each type of object I´d want to get from it.
Thanks in advance,
Ariel
Are you using JSON.NET? Generics seem to be the right answer, at any rate. Something like this:
public T CreateAnimal<T>(string json) {
return JsonConvert.DeserializeObject<T>(json);
}
Note that in order to use this, you would have to know ahead of time which type of object you would expect in the json, so you can call it like this:
Tiger t = CreateAnimal<Tiger>(tigerJson);
To prevent bloated code, you could instantiate your animal objects convention-based:
Activator.CreateInstance("YourAssemblyNameContainingAnimalTypes", animalString);

Storing ab object in a class library

I have an object (a system GUID) I need to use repeatedly in my class library. I would like to store it somewhere. Whats the best way to do that? Im thinking i could serialize and deserialize the object but it dosent seem like the simplest solution.
Just convert it into a string, store this in your Resources/App.Confing/Whatever (even as a constant in some of your classes) and use the constructor of Guid with the string overload to load it.

Is there any way to override what string value my custom type gets converted to when serializing via DataContract?

In my music/rhythm game, I using serialization in order to save user-created simfiles (think music tabs or notecharts). Nothing too earth-shattering there. But, I'm using a DataContract in order to perform the serialization, because:
1) I need private and protected fields serialized as well. I don't care if they're visible, mainly due to...
2) I'd like for the user to be able to edit the serialized file in his/her favorite text editor and be able to load these into the game (these files will be used to represent musical notes in the game, think StepMania simfiles).
One of my custom datatypes I'd like to serialize is a Fraction class I've created:
using System.Runtime.Serialization;
namespace Fractions {
[DataContract(Namespace="")] // Don't need the namespaces.
public sealed class Fraction {
// NOTE THAT THESE ARE "READONLY"!
[DataMember(Name="Num", Order=1)] private readonly long numer;
[DataMember(Name="Den", Order=2)] private readonly long denom;
// ...LOTS OF STUFF...
public static Fraction FromString(string str) {
// Try and parse string and create a Fraction from it, and return it.
// This is static because I'm returning a new created Fraction.
}
public override ToString() {
return numer.ToString() + "/" + denom.ToString();
}
}
}
Testing this, it works decently, serializing into an XML fragment of the form:
<Fraction>
<Num>(INT64 VALUE AS STRING)</Num>
<Den>(INT64 VALUE AS STRING)</Den>
</Fraction>
Now, I could just be happy with this and go on my merry coding way. But I'm picky.
My end users will probably not be super familiar with XML, and there's a LOT of more complex datatypes in my game that will include a lot of Fractions, so I'd much rather prefer to be able to represent a Fraction in the XML simfile as such (much more concisely):
<Fraction>(NUMERATOR)/(DENOMINATOR)</Fraction>
However, I'm at a loss as to how to do this without breaking automatic (de)serialization. I looked into the IXmlSerializable interface, but I was shut down by the fact that my datatype needed to be mutable in order for it to work (ReadXml() doesn't return a new Fraction object, but instead seems to flash-instantiate one, and you have to fill in the values manually, which doesn't work due to the readonly). Using the OnSerializing and OnDeserialized attributes didn't work either for the same reason. I'd REALLY prefer to keep my Fraction class immutable.
I'm guessing there's a standard procedure by which primitives are converted to/from strings when serializing to XML. Any numeric primitives, for instance, would have to be converted to/from strings upon serializing/deserializing. Is there any way for me to be able to add this sort of automatic string from/to conversion to my Fraction type? If it were possible, I'd imagine the serializing procedure would look something like this:
1) Serialize this complex datatype which contains Fraction fields.
2) Start serializing the [DataMember] fields.
3) Hey, this field is a Fraction object. Fractions are able to represent themselves fully as a string. Write that string out to the XML directly, instead of diving into the Fraction object and writing out all its fields.
...
Deserialization would work the opposite way:
1) Deserialize this data, we're expecting so-and-so data type.
2) Start deserializing fields.
3) Oh look, a Fraction object, I can just go ahead and read the content string, convert that string into a new Fraction object, and return the newly-created Fraction.
...
Is there anything I can do to accomplish this? Thanks!
EDIT: Data Contract Surrogates seem like the way to go, but for the life of me I can't seem to understand them or have them work in my game. Or rather, they add some nasty automatic namespace and ID fields to my serialized elements.
I guess that you can probably use Data Contract Surrogates.
But even simpler way would be to have a private string member fractionString within your type that will represent the string representation of your Type. You have to initialize it only during object construction (as your type is immutable). Now you can skip num and den from serialization and mark your fractionString field as DataMember. Downside to the approach is additional space consumption.
public sealed class Fraction {
private readonly long numer;
private readonly long denom;
[DataMember(Name="Fraction")
private string fractionString;
EDIT: Never mind, just re-read what you want and realized above won't work.
I had a similar problem, though in my case I was using the Type-Safe-Enumeration pattern. In each case, when you write your DataContract, you are specifying in the elements containing the non-simple data type C# decides to make the class into an element and then look to the class for that data contract.
Unfortunately, that is not what either of us wants.
My solution was two part:
1) In the complex class we want to include (Fraction in your case) provide methods to serialize and deserialize the object into a string. (I used the cast operators because that carries the meaning best to me):
class Complex
{
...
// NOTE: that this can be implicit since every Complex generates a valid string
public static implicit operator string(Complex value)
{
return <... code to generate a string from the Complex Type...>;
}
// NOTE: this must be explicit since it can throw an exception because not all
// strings are valid Complex types
public static explicit operator Complex(string value)
{
return <... code to validate and create a Complex object from a string ...>;
}
...
}
2) Now, when you use a Complex type object in another class, you define the DataContract with a string property and use a backing value of the actual Complex type:
[DataContract]
class User
{
...
[DataMember]
public string MyComplex
{
get { return m_MyComplex; }
set { m_myComplex = (Complex)value; }
}
// NOTE that this member is _not_ part of the DataContract
Complex m_myComplex;
...
}
While I admit it is not an ideal solution, requiring the presence of additional code in the using class, it does allow arbitrary string representation of a complex class within the DataContract format without additional layers that would otherwise be necessary.

XmlConvert and nullable results?

In my project I receive an XmlElement of which I have to parse a few properties back to a class.
For mapping these I use the XmlConvert class. But the source being XML there often are empty nodes or nodes that are not readable. Rather then throwing a bunch of errors, I want to get a NULL back to store in my class.
I started making an XmlConvertExtentions class that does things in the following spirit:
public static class XmlConvertExtentions
{
public static int? ToNullableInt32 (this XmlConvert c, string s){
try{ return XmlConvert.ToInt32(s); }
catch{ return null; }
}
}
I strongly believe that I'm not the first developper in need of such a functionality and I'm wondering if I'm not inventing yet another wheel.
Furthermore I feel like I'm inventing a really ugly wheel. The try catch feels bad. Is there a better way?
--EDIT--
And now I also noticed that it doesn't even work :P
I think it's because you can't extend static classes.
If the node is null or empty, what is s?
How about just:
if(string.IsNullOrEmpty(s)) return null;
return XmlConvert.ToInt32(s);
Note also that LINQ-to-XML has more graceful handling of these conversions (via casts).
I don't know if it is possible in your case / situation, but have you already though on using the XML serialization classes, and deserialize the XML by the XmlSerializer classes directly into instances of your custom class, instead of doing it all manually ?

How to use XmlSerializer to deserialize into an existing instance?

Is it somehow possible to use the XmlSerializer to deserialize its data into an existing instance of a class rather than into a new one?
This would be helpful in two cases:
Easily merge two XML files into one object instance.
Let object constructer itself be the one who is loading its data from the XML file.
If the is not possible by default it should work by using reflection (copying each property after the deserialisation) but this would be an ugly solution.
Basically, you can't. XmlSerializer is strictly constructive. The only interesting thing you can do to customize XmlSerializer is to implement IXmlSerializable and do everything yourself - not an attractive option (and it will still create new instances with the default constructor, etc).
Is xml a strict requirement? If you can use a different format, protobuf-net supports merging fragments into existing instances, as simply as:
Serializer.Merge(source, obj);
I think you're on the right track with the Reflection idea.
Since you probably have a wrapper around the XML operations anyway, you could take in the destination object, do the deserialization normally into a new object, then do something similar to cloning by copying over one by one only the properties holding non-default values.
It shouldn't be that complex to implement this, and it would look to consumers from the rest of your application just like in-place deserialization.
I hit the same problem a few weeks ago.
I put a method Deserialize(string serialized form) in the ISelfSerializable interface that an entity class of mine implemented. I also made sure the interface forced the class to have a default constructor.
In my factory I created an object of that type and then deserialized the string into it.
This is not thread safe thing to do... But you can do:
[Serializable]
public class c_Settings
{
static c_Settings Default;
public static SetExistingObject(c_Settings def)
{
Default = def;
}
public string Prop1;
public bool Prop2;
public c_Settings()
{
if (Default == null)
return;
MemberInfo[] members = FormatterServices.GetSerializableMembers(typeof(c_Settings));
FormatterServices.PopulateObjectMembers(this, members, FormatterServices.GetObjectData(Default, members));
}
}
This way you feed your object to deserialiser and deserialiser only overwrites whatever is written in .xml.

Categories