My Class
[System.Serializable]
public class StallData
{
public StallData(ulong stallID, stallSurfaceTextureData)
{
StallID = stallID;
StallSurfaceTextureData = stallSurfaceTextureData;
}
[field: SerializeField]
public ulong StallID{ get; private set; }
[field: SerializeField]
public StallSurfaceTextureData StallSurfaceTextureData { get; private set; }
}
[System.Serializable]
public class StallSurfaceTextureData
{
public StallSurfaceTextureData( int floorTextureID, int leftTextureID, int right, int back)
{
Debug.LogFormat($" f {floorTextureID} l {leftTextureID} r {right} b {back}");
BackWallTextureID = back;
LeftWallTextureID = leftTextureID;
RightWallTextureID = right;
FloorTextureID = floorTextureID;
}
[field: SerializeField]
public int BackWallTextureID { get; private set; }
[field: SerializeField]
public int LeftWallTextureID { get; private set; }
[field: SerializeField]
public int RightWallTextureID { get;private set; }
[field: SerializeField]
public int FloorTextureID { get; private set; }
}
using newtonsoft-json when I am converting my JSON to this class I am getting back, left & right value 0 and for floor, I am getting the correct value.
I am unable to find the reason for it.
Unity version 2021.3.12f1
this is my JSON
{
"StallID": 889448,
"StallSurfaceTextureData":
{
"BackWallWallTextureID": 0,
"LeftWallWallTextureID": 1,
"RightWallWallTextureID": 2,
"FloorTextureID": 3
}
}
I renamed the parameter name, and one time it worked then again I am getting the same issue.
Edit:
I have changed the parameter name in JSon but still the issue persists. The only way it is working is if I am keeping the parameter name and the variable name inside the class is same. I am not getting how the Parameter name is affecting the value assignment in the class?
for ex:
If I keep my class like this it will work
[System.Serializable]
public class StallSurfaceTextureData
{
public StallSurfaceTextureData( int floorTextureID, int leftWallTextureID, int rightWallTextureID, int backWallTextureID)
{
Debug.LogFormat($" f {floorTextureID} l {leftWallTextureID} r {rightWallTextureID} b {backWallTextureID}".ToGreen());
BackWallTextureID = backWallTextureID;
LeftWallTextureID = leftWallTextureID;
RightWallTextureID = rightWallTextureID;
FloorTextureID = floorTextureID;
}
[field: SerializeField]
public int BackWallTextureID { get; private set; }
[field: SerializeField]
public int LeftWallTextureID { get; private set; }
[field: SerializeField]
public int RightWallTextureID { get;private set; }
[field: SerializeField]
public int FloorTextureID { get; private set; }
}
Unity need to have the same to the letter variables name in JSON and class.
You have BackWallTextureID in JSON and BackWallTextureId in class.
I tried JsonConvert.DeserializeObject(json) - no any problem, I guess because you constructor input parameters are ignored since they are not exist for Newtonsoft.Json. If you want to use a constructor, input parameters should be the same as json ( case insensitive by default).
Related
I have many entities that use a UserId property of the same type.
Can I define a type (string or int, ...) that I can easily change as a variant for all?
Example:
public class Entity_One
{
public DefineMyType UserId { get; set; }
public string Property_Entity_One { get; set; }
}
public class Entity_Two
{
public DefineMyType UserId { get; set; }
public string Property_Entity_Two { get; set; }
}
const DefineMyType = string;
// or const DefineMyType = int;
// or const DefineMyType = Guid;
Constants can't be used like that.
Preprocessor may be used.
But we can use a generic:
public abstract class AbstractID<T>
{
static protected T Last = default;
public T Value { get; protected set; } // or perhaps init only with C# 9
}
Thus we can define some specialized IDs like:
public class NumberID<T> : AbstractID<T> where T : struct, IComparable, IFormattable
{
public NumberID()
{
Value = (T)( (dynamic)Last + 1 );
Last = Value;
}
}
public class GuidID : AbstractID<Guid>
{
public GuidID()
{
Value = Guid.NewGuid();
Last = Value;
}
}
public class StringID : AbstractID<string>
{
private string Generate()
{
return ...
}
public StringID()
{
Value = Generate();
Last = Value;
}
}
Then we can set the "default" ID type:
public class ManagedID : NumberID<int>
{
}
Or:
public class ManagedID : GuidID
{
}
Therefore we can easily change ManagedID for all code using it.
It only requires to change the ancestor class in the declaration.
And now that works:
public class EntityOne
{
public ManagedID UserId { get; } = new ManagedID();
public string PropertyEntityOne { get; set; }
}
public class EntityTwo
{
public ManagedID UserId { get; } = new ManagedID();
public ManagedID EntityOneId { get; }
public string PropertyEntityTwo { get; set; }
public EntityTwo(EntityOne one)
{
EntityOneId = one.UserId;
}
}
Test
var entity1 = new EntityOne();
var entity2 = new EntityOne();
var entity3 = new EntityTwo(entity1);
Console.WriteLine(entity1.UserId.Value);
Console.WriteLine(entity2.UserId.Value);
Console.WriteLine(entity3.UserId.Value + $" ({entity3.EntityOneId.Value})");
Result with an integer
1
2
3 (1)
Result with a GUID
3a189122-60fd-4dc5-9d7f-3cc4c83375f9
37a9c7de-8ed5-4d02-a1b9-f414db051335
2de962d6-cc91-4e78-b3dc-28acb0ba7f3b (3a189122-60fd-4dc5-9d7f-3cc4c83375f9)
Warning
Here, the use of numbers is very basic and not really reliable, especially beyond a local machine and after stopping the execution of the current process. Thus persistence somewhere of the last value is required for a real database, like in a config file or whatever.
GUID vs INT IDENTITY
Guid vs INT - Which is better as a primary key?
Int for identity/primary key and Guid for public identifier, best practices?
I have the following models
public class CustomEvent
{
private string _tag;
public int Id { get; set; }
public int PId { get; set; }
public DateTimeOffset TimeStamp { get; set; }
public string Mentor { get; set; }
public string Type { get; set; }
public string Tag
{
get => _tag;
set
{
_tag = GetTagTypeList.GetTagType(typeof(TagType)).Contains(value) ? value : "Unspecified";
}
}
}
public static class TagType
{
public const string Unspecified = "Unspecified";
public const string AmxPersonalItemCreate = "Amx.PersonalItem.Create";
public const string AmxPersonalItemUpdate = "Amx.PersonalItem.Update";
public const string AmxPersonalItemDelete = "Amx.PersonalItem.Delete";
public const string AmxRegionCreate = "Amx.Region.Create";
public const string AmxRegionUpdate = "Amx.Region.Delete";
public const string AmxRegionDelete = "Amx.Region.Update";
}
public class GetTagTypeList
{
public static List<String> GetTagType(Type type)
{
return type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
.Select(x=>x.GetValue(null).ToString()).ToList();
}
}
The above code restricts the setter to the list of static values. However this is very inefficient, as it is reflecting over the class every single time the method [GetTagType] is called.
I now have a requirement to Create a TagType class with a private constructor, and static values.
Given the values to be expressed have "." in them, it will require a custom json serializer as well.
I have read somewhere that a solution could be to use nested classes to get values which match the string being created.
i.e. for "Amx.PersonalItem.Create" we could create a class which resemble:
public static class Amx
{
public static class PersonalItem
{
public static TagType Create { get; } = new TagType("Amx.PersonalItem.Create");
}
}
I need to integrate the above example into my CustomEvent Class.
Or any other solution that uses static values to achieve same result.
Would appreciate any help ?
How about making a static item in the class that builds the list and stores it in a static variable? That means you can build the list once no matter how many times your setter is called. You still have to search the list but you don't need to use reflection.
I have a c# object 'Product' with a property called: Offset
In the database the field is of type nvarchar(50)
I will be storing a JSON value in it such as the following: { "y": 0, "m": 0, "d": 0 }
I would like to know a good way of working with a property like this in my code. Here is how I currently am doing it:
public class Product
{
public int Id {get; set;}
public string Description {get; set;}
public decimal Price {get; set;}
public int OffsetYears { get; set; }
public int OffsetMonths { get; set; }
public int OffsetDays { get; set; }
public string Offset
{
get
{
Offset offset = new Offset()
{
Y = OffsetYears,
M = OffsetMonths,
D = OffsetDays
};
return JsonConvert.SerializeObject(offset);
}
set
{
OffsetObj offset = JsonConvert.DeserializeObject<Offset>(value);
OffsetYears = offset.Y;
OffsetMonths = offset.M;
OffsetDays = offset.D;
}
}
private class OffsetObj
{
public int Y { get; set; }
public int M { get; set; }
public int D { get; set; }
}
}
So then when I accept values from the User in the UI I would set the OffsetYears, OffsetMonths, and OffsetDays properties.. So in my repository I can just save Offset.
And when retrieving values from the database I will simply work with OffsetYears, OffsetMonths, and OffsetDays properties in my code.
Is there a better way to handle this sort of thing? I just feel like I am not utilizing all of my c# resources. Like what if another developer accidentally sets Offset through the code assuming any format of string can go in it.
Or am I better off just creating 3 separate integer fields in the database and avoiding all of this...
I would hold the values in a field of your private type. Consider this approach:
public class Product
{
private OffsetObj _offset = new OffsetObj();
public int Id { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public int OffsetYears
{
get { return _offset.Y; }
set { _offset.Y = value; }
}
public int OffsetMonths
{
get { return _offset.M; }
set { _offset.M = value; }
}
public int OffsetDays
{
get { return _offset.D; }
set { _offset.D = value; }
}
public string Offset
{
get
{
return JsonConvert.SerializeObject(_offset);
}
set
{
_offset = JsonConvert.DeserializeObject<OffsetObj>(value);
}
}
private class OffsetObj
{
public int Y { get; set; }
public int M { get; set; }
public int D { get; set; }
}
}
This way, the field offset will hold the values for the offset.
Like what if another developer accidentally sets Offset through the code assuming any format of string can go in it.
JsonConvert will throw a JsonReaderException if trying to set the Offset property to a string that does not match JSON-format. In my opinion this is expected. To clarify further, you could name your property to OffsetJson.
However, I fail to see the benefit in this simple case to store your information as JSON. If you are using a relational database, you may as well just store your values in separate columns.
I have this class
[global::System.Serializable, global::ProtoBuf.ProtoContract(Name=#"MarketDataEntry")]
public partial class MarketDataEntry : global::ProtoBuf.IExtensible
{
// some other properties
private float _EntryPrice;
[global::ProtoBuf.ProtoMember(270, IsRequired = true, Name=#"EntryPrice", DataFormat = global::ProtoBuf.DataFormat.FixedSize)]
public float EntryPrice
{
get { return _EntryPrice; }
set { _EntryPrice = value; }
}
}
This was working as expected. I changed the type from float to decimal for the EntryPrice property, and now I'm getting Exception message on this line
Serializer.Serialize(stream, toSerialize);
Exception message says
IExtensible is not supported in structs or classes with inheritance
Error message itself is confusing, because I made no change but float to decimal. Can that change be reason for this exception message? And what should I check for to understand where problem comes from?
I'm using protobuf-net v.2.0.0.664 on .net 4.0
EDIT
Regarding Marc's comment, MarketDataEntry is a base class for another protocontract.
[Serializable]
[ProtoContract]
public sealed class MarketData : ProtobufMarketData, IEntity
{
[ProtoMember(1)]
public long Id { get; set; }
[ProtoMember(2)]
public DateTime TransformTime { get; set; }
[ProtoMember(3)]
public DateTime CreationTime { get; set; }
[ProtoMember(4)]
public DateTime ConsumtionTime { get; set; }
[ProtoMember(5)]
public int FailedToBeConsumedCounter { get; set; }
}
EDIT 2
So what actually is being serialized is instance of MarketData, which inherits from ProtobufMarketData, which in turn contains property of type List, so I think that's where problem resist. List of MarketDataEntry objects, which contain decimal property.
[global::System.Serializable, global::ProtoBuf.ProtoContract(Name=#"ProtoBufMarketData")]
[ProtoBuf.ProtoInclude(10000, typeof(MarketData))]
public partial class ProtoBufMarketData : global::ProtoBuf.IExtensible
{
public ProtoBufMarketData() {}
private readonly global::System.Collections.Generic.List<CoreX.Shared.Entities.MarketDataDefs.MarketDataEntry> _MarketDataEntries = new global::System.Collections.Generic.List<CoreX.Shared.Entities.MarketDataDefs.MarketDataEntry>();
[global::ProtoBuf.ProtoMember(10004, Name = #"MarketDataEntries", DataFormat = global::ProtoBuf.DataFormat.Default)]
public global::System.Collections.Generic.List<CoreX.Shared.Entities.MarketDataDefs.MarketDataEntry> MarketDataEntries
{
get { return _MarketDataEntries; }
}
}
I have the following class:
[Serializable]
public class SerialAssassin
{
public Hero hero;
public Point heroPB;
public Boss boss;
public Point bossPB;
public Attack attack;
public Point attackPB;
public HPMeter bossHP;
public Point bossHPPB;
public PPMeter heroPP;
public Point heroPPPB;
public Rectangle bossRect;
public Rectangle attackRect;
public int heroState;
public int stepRate;
public int attackDirection;
public int attackLoop;
public int contadorPaso;
public int contadorPasoBoss;
public int bossTop, bossLeft;
public int bossState;
public int bossHealth;
public int bossHPCap;
public int opa;
public int battlesWon;
public int mainBossCounter;
public int ppleft;
public bool paso;
public bool inStadium;
public bool fading;
public bool fightingMainBoss;
public bool fainted;
public string currentPokemon;
}
I'm having problems reading the data from the XML, which was written as follows:
XmlSerializer serializer = new XmlSerializer(typeof(SerialAssassin));
TextWriter textWriter = new StreamWriter(#"..\..\Resources\saveState.xml");
serializer.Serialize(textWriter, serial);
textWriter.Close();
From there, I don't quite know how to read the data. Plus the fact that the XML doesn't serialize the objects of Hero, Boss, Attack, HPMeter, PPMeter.
Hero class:
public class Hero
{
int state = 0;
int x, y;
string path;
Image img;
//methods
}
I'd be grateful if you would be so kind as to explain to me how to load those objects/primitives and then use them.
IIRC, the XmlSerializer checks for properties, not fields. (I think it can use public fields, but you really ought to switch to properties anyway) In addition, classes do not need to be marked as Serializable. (Serializable is used for others such as binary and SOAP serializers)
Replace your fields with properties with public getters and setters. In addition, make sure your other classes (such as Hero, Point, Boss) are all also serializable according to XmlSerializer's rules:
public class SerialAssassin
{
public Hero hero { get; set; }
public Point heroPB { get; set; }
public Boss boss { get; set; }
public int heroState { get; set; }
...
To deserialize, use its Deserialize method (http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.deserialize.aspx):
Stream xmlInputStream = ... //get your file stream, or TextReader, or XmlReader
XmlSerializer deserializer = new XmlSerializer(typeof(SerialAssassin));
SerialAssassin assassin = (SerialAssassin)deserializer.Deserialize(xmlInputStream)
EDIT: Looking at your sample Hero class, it's not serializing any of its values because you have declared them all to be private. Make them public instead.
public class Hero
{
public int state {get; set; }
public int x { get; set; }
public int y { get; set; }
public string path { get; set; }
[XmlIgnore]
public Image img { get; set; }
}
I suspect that Image will not be serializable, so you may want to store the image's file path (or some other identifying information) so you can save/load it. [XmlIgnore] will instruct the XmlSerializer to ignore that property so it doesn't fail during serialization/deserialization.
XmlSerializer serializer = new XmlSerializer(typeof(SerialAssassin));
SerialAssassin assassin;
using(var reader = File.OpenText(#"..\..\Resources\saveState.xml"))
{
assassin = (SerialAssassin)serializer.Deserialize(reader);
}