c# How to transform multiple structs into 1 bigger - c#

i have 6 structs for the player and also for the 5 bots. Everyone of them have some different variables and some that are equal to the other ones.I declare them like this
public struct Player
{
public static int Chips;
public static int Type;
public static int Power;
public static bool bot1Turn;
public static bool bot1FoldTurn;
public static AnchorStyles playerCardsAnchor = AnchorStyles.Bottom;
}
public struct Bot1
{
public static int bot1Chips;
public static int bot1Type;
public static int bot1Power;
public static bool bot1Turn;
public static bool bot1FoldTurn;
public static AnchorStyles bot1CardsAnchor = AnchorStyles.Left;
}
public struct Bot2
{
public static int bot2Chips;
public static int bot2Type;
public static int bot2Power;
public static bool bot2Turn;
public static bool bot2FoldTurn;
public static AnchorStyles bot2CardsAnchor = AnchorStyles.Right;
}
public struct Bot3
{
public static int bot3Chips;
public static int bot3Type;
public static int bot3Power;
public static bool bot3Turn;
public static bool bot3FoldTurn;
public static AnchorStyles bot3CardsAnchor = AnchorStyles.Top;
}
public struct Bot4
{
public static int bot4Chips;
public static int bot4Type;
public static int bot4Power;
public static bool bot4Turn;
public static bool bot4FoldTurn;
public static AnchorStyles bot4CardsAnchor = AnchorStyles.Bottom | AnchorStyles.Right;
}
public struct Bot5
{
public static int bot5Chips;
public static int bot5Type;
public static int bot5Power;
public static bool bot5Turn;
public static bool bot5FoldTurn;
public static AnchorStyles bot5CardsAnchor = AnchorStyles.Top | AnchorStyles.Left;
}
Later on i add the values in a static constructor :
static MainPoker()
{
Player.Chips = 100000;
Player.Power = 0;
Player.Type = -1;
Player.playerTurn = true;
Player.playerFoldTurn = false;
}
Now should i keep all the 6 structs like this, or there's some other way to put them all together ? I'm looking for something like interface but it should also be able to hold static variables .. Any suggestions ?

Structs are value types, while classes are reference types. You almost certainly want to use classes for this type of thing.
You have many properties (which you have implemented as fields) in common between players and bots, and between the different "bot numbers". You decided to give all of those properties different names, which makes it difficult to simplify the code.
Your fields are declared static. I would suggest making them instance fields (or probably instance properties).
If you make those changes, you can use inheritance to put similar things in a common base type
public class Agent
{
public int Chips;
public int Type;
public int Power;
public bool Turn;
public bool FoldTurn;
public AnchorStyles CardsAnchor;
}
public class Player : Agent
{
public Player() { CardsAnchor = AnchorStyles.Bottom; }
// Anything that makes a player different here
}
public class Bot : Agent
{
// Anything that makes a bot different here
public Bot(AnchorStyles style)
{
CardsAnchor = style;
}
}
Player player = new Player();
Bot bot1 = new Bot(AnchorStyles.Left);
Bot bot2 = new Bot(AnchorStyles.Right);
You an use properties in your code rather than fields. They will seem to behave similarly in code consuming the class, but properties afford more flexibility because they provide a layer between the value of something and how it is stored behind the scenes (for example, a property can be calculated based on the value of other properties or multiple backing fields). Using properties, you would instead write
public class Agent
{
public int Chips { get; set; }
public int Type { get; set; }
public int Power { get; set; }
public bool Turn { get; set; }
public bool FoldTurn { get; set; }
public AnchorStyles CardsAnchor { get; set; }
}

You don't want structs, you want classes (except you really want structs, but then you would know it)
and you are mixing classes with instances of classes (objects).
Generate just one Player class and then create instances from it:
public class Player
{
public int Chips { get; set; }
public int Type { get; set; }
public int Power { get; set; }
public bool BotTurn { get; set; }
public bool BotFoldTurn { get; set; }
public AnchorStyles PlayerCardsAnchor { get; }
public Player(AnchorStyles playerCardsAnchor, more parameters for properties)
{
PlayerCardsAnchor = playerCardsAnchor;
// set other properties here
}
}
MainPoker()
{
var player = new Player(AnchorStyles.Bottom, more parameters);
var bot1 = new Player(AnchorStyles.Left, more parameters);
//more bots
}
If you need a static way to acces these, create a static class that holds references to these instances.
public static class PokerTable
{
public static Player Player { get; }
public static Player Bot1 { get; }
// more bots
static PokerTable()
{
Player = new Player(AnchorStyles.Bottom, more parameters);
Bot1 = new Player(AnchorStyles.Left, more parameters);
//more bots
}
}
Then you can access the instances in a static way using
PokerTable.Player.Chips = 10;

Related

C# object instance wont return values

Currently working on a text based GTA type game as part of a project. Having difficulty understand how C# handles classes/objects/values from one file to another..
In my main Program.cs file I have:
public static Data CreatePlayer()
{
//INIT PLAYER INSTANCE (playername, credits, playerhealth, armourhealth, wantedlevel,
currentlocation)
Data Player = new Data("PLAYER1", 100, 10, 0, 0, "DOWNTOWN");
return Player;
}
public static void Main(string[] args)
{
var Player = CreatePlayer();
Data.Stats(Player);
}
And in my Data.cs file i have:
public class Data
{
//create private fields(vars)
private string playername;
private uint credits;
private uint playerhealth;
private uint armourhealth;
private uint wantedlevel;
private string currentlocation;
//create public props(values)
public string PLAYER_NAME
{ get; set; }
public uint CREDITS
{ get; set; }
public uint PLAYER_HEALTH
{ get; set; }
public uint ARMOUR_HEALTH
{ get; set; }
public uint WANTED_LEVEL
{ get; set; }
public string CURRENT_LOCATION
{ get; set; }
//create class constructor and params
public Data(string playername, uint credits, uint playerhealth, uint armourhealth, uint wantedlevel, string currentlocation)
{
this.playername = PLAYER_NAME;
this.credits = CREDITS;
this.playerhealth = PLAYER_HEALTH;
this.armourhealth = ARMOUR_HEALTH;
this.wantedlevel = WANTED_LEVEL;
this.currentlocation = CURRENT_LOCATION;
}
public static void Stats(Object player)
{
Type t = player.GetType();
PropertyInfo[] props = t.GetProperties();
foreach (var prop in props)
if (prop.GetIndexParameters().Length == 0)
{
Console.WriteLine("{0}: {1}", prop.Name, prop.GetValue(player));
Console.WriteLine("---------------------");
}
else
{
Console.WriteLine(" {0} ({1}): <Indexed>", prop.Name,
prop.PropertyType.Name);
}
}
These 2 files do not seem to communicate to eachother. I get no errors in the console, but all the values when Data.Stats() is called on the Player object come back as 0 if a uint or blank if a string.
You never assign a value to the public properties of Data, which is why they always return their default values of zero for an unit and null for string.
Your Data class seems half setup for private fields to be the backing values for the public properties, but you're not using them. For example:
private string playername;
public string PLAYER_NAME { get; set; }
The public property PLAYER_NAME is not using playername here. It will create its own backing field automatically during compilation. The get and set are automatically implemented to use that backing field. If you wanted to use your own, the property would need to look like this:
public string PLAYER_NAME {
get {
return playername;
}
set {
playername = value;
}
}
However, in your case having your own backing fields isn't necessary. You can just assign directly to the public properties in the constructor and let it handle the backing fields, and remove your own. It's clearer that way and less code. Generally having your own backing fields is only necessary when you need more complex logic in the property getters and setters.

restrict a setter to a static list of values

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.

Assign additional attributes to types like int, float for reflection purposes

I am trying to automate the display (gathering via reflection) of my variables which are located in specific scripts in Unity. The trouble is assigning custom values (for example: "string DisplayName", "bool DisplayMe", "bool WriteMe" etc.). When it comes to my custom classes I understand how I would do it, but I would like to avoid remaking types like float, string, int etc. for this purpose.
For example, let's say I have:
public class myBaseClass
{
public string Name = "Display Name";
public bool AmReadable = true;
public bool AmWritable = true;
}
Then:
public class myDoubleFloat: myBaseClass
{
public float ValueFirst;
public float ValueSecond;
}
So in some scripts in Unity I define it:
public class SomeScriptOnGameObject : MonoBehaviour
{
public myDoubleFloat myFirstVariable{get; set;}
public float mySecondVariable{get; set;}
}
So later on with reflection I can check whether "myFirstVariable" should be read, it's display name etc. - while for "mySecondVariable" I cannot perform this check. How do I go about this without reinventing the wheel and making a class for each of these types like float, string, int, List etc.?
You can define a generic wrapper:
public class MyProperty<T>
{
private T _value;
public T Get() => _value;
public T Set(T newValue) => _value = newValue;
public string Name { get; set; }
public bool AmReadable { get; set; }
public bool AmWritable { get; set; }
}
And make your properties's getters and setter to map to some backing fields of type MyProperty<T>:
public class SomeScriptOnGameObject : MonoBehaviour
{
private MyProperty<MyDoubleFloat> _myFirstVariable;
private MyProperty<float> _mySecondVariable;
public MyDoubleFloat MyFirstVariable
{
get => _myFirstVariable.Get();
set => _myFirstVariable.Set(value);
}
public float MySecondVariable
{
get => _mySecondVariable.Get();
set => _mySecondVariable.Set(value);
}
public SomeScriptOnGameObject()
{
_myFirstVariable = new MyProperty<MyDoubleFloat>
{
//configuration
};
_mySecondVariable = new MyProperty<float>
{
//configuration
};
}
}
If you want to be fancy you can even add an implicit operator to get rid of Get() and make any T assignable from MyProperty<T>:
public class MyProperty<T>
{
private T _value;
public T Set(T newValue) => _value = newValue;
public string Name { get; set; }
public bool AmReadable { get; set; }
public bool AmWritable { get; set; }
public static implicit operator T(MyProperty<T> myProperty) =>
myProperty != null ? myProperty._value : default;
}
And:
public MyDoubleFloat MyFirstVariable
{
get => _myFirstVariable;
set => _myFirstVariable.Set(value);
}
Wrapping value objects (int, float, etc.) is probably not the best approach. Besides the additional complexity (and possibility for bugs), you are now bloating the memory footprint of your game.
(I'm intentionally avoiding newer C# syntax in these examples)
Since you are already in a reflection context, instead of wrapping your value objects, I'd suggest an attribute-based approach. For example:
public class SomeScriptOnGameObject
{
[DisplayName("First Variable"), Writable]
public float FirstVariable { get; set; }
[DisplayName("Second Variable")]
public float SecondVariable { get; set; }
[DisplayName("Some Field")]
public float Field;
public float FieldWithNoAttributes;
}
This has the advantage of keeping the metadata of the fields in the metadata, instead of carrying around a copy of everything with every instance you create.
The actual attributes are easy to create, also. I'll start with the simplest one, WritableAttribute:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class WritableAttribute : Attribute
{
}
This empty class is all that's needed to mark a field or property as "Writable". The AttributeUsage marks this as only valid on fields and properties (not, for example, a class).
The other attribute, DisplayName, is only slightly more complex:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class DisplayNameAttribute : Attribute
{
public string DisplayName { get; private set; }
public DisplayNameAttribute(string displayName)
{
DisplayName = displayName;
}
}
The main difference is the constructor with the displayName argument, and the DisplayName property. This forces the compiler to expect an argument to the attribute.
With some extension methods, you can make things very clean:
public static class AttributeExtensions
{
public static bool IsWritable(this MemberInfo memberInfo)
{
return memberInfo.GetCustomAttributes(typeof(WritableAttribute)).Any();
}
public static string DisplayName(this MemberInfo memberInfo)
{
var displayNameAttribute =
memberInfo.GetCustomAttributes(typeof(DisplayNameAttribute))
.FirstOrDefault() as DisplayNameAttribute;
return displayNameAttribute == null ? null : displayNameAttribute.DisplayName;
}
public static PropertyInfo Property<T>(this T _, string propertyName)
{
return typeof(T).GetProperty(propertyName);
}
public static FieldInfo Field<T>(this T _, string fieldName)
{
return typeof(T).GetField(fieldName);
}
}
(Since you mentioned you are already using reflection, you might not need the last two methods there.)
Finally, a simple XUnit test to demonstrate:
public class UnitTest1
{
[Fact]
public void Test1()
{
var obj = new SomeScriptOnGameObject();
Assert.True(obj.Property("FirstVariable").IsWritable());
Assert.False(obj.Property("SecondVariable").IsWritable());
Assert.False(obj.Field("Field").IsWritable());
Assert.Equal("First Variable", obj.Property("FirstVariable").DisplayName());
Assert.Equal("Second Variable", obj.Property("SecondVariable").DisplayName());
Assert.Equal("Some Field", obj.Field("Field").DisplayName());
Assert.Null(obj.Field("FieldWithNoAttributes").DisplayName());
}
}

Mapping 2 classes with same properties

I duplicated a Class1 in a Class2 with the same properties but not all ones. In my context, I have a Class1 obj (o1) initialised with values and I want to change some ones with values of a Class2 obj (o2) without losing the o1 data (values which aren't in o2). Manually, I need to reassignate o1 with values of o2 so I would like to find an automatic way like mapping the classes.
Classes:
public class Class1
{
public bool Property1;
public int Property2;
public string Property3;
public bool Property4;
public int Property5;
public string Property6;
public bool Property7;
public int Property8;
public string Property9;
public bool Property10;
public int Property11;
public string Property12;
public bool Property13;
public int Property14;
public string Property15;
public bool Property16;
public int Property17;
public string Property18;
public bool Property19;
public int Property20;
}
public class Class2
{
public bool Property1;
public int Property2;
public string Property3;
public bool Property7;
public int Property8;
public string Property9;
public bool Property10;
public int Property11;
public string Property12;
public bool Property13;
public int Property14;
public string Property15;
public bool Property16;
public int Property17;
public string Property18;
public bool Property19;
public int Property20;
public Class1 ToClass1()
{
return new Class1()
{
Property1 = Property1,
Property2 = Property2,
Property3 = Property3,
Property7 = Property7,
...
Property20 = Property20
};
}
}
If I do ToClass1(), I lose the values of Property4, Property5 and Property6 of the o1.
What I do now:
// o1 and o2 are initialised with values.
o1.Property1 = o2.Property1;
o1.Property2 = o2.Property2;
o1.Property3 = o2.Property3;
o1.Property7 = o2.Property7;
...
o1.Property20 = o2.Property20;
you need to use automapper and configure your mapping rule to ignore the properties you wont want to map.
Look at this link

Load object data from XML in C#

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);
}

Categories

Resources