---Post updated after to many errors found on first code---
I have some trouble with Boolean on Object.
This is my Chunk class containing a Zone struct :
using System;
using System.Collections.Generic;
public class Test
{
public static void Main()
{
new Chunk();
}
}
public class Chunk {
List <Zone> zones;
public Chunk() {
// Create 3 elements on the List
this.zones = new List<Zone>();
this.zones.Add(new Zone(1));
this.zones.Add(new Zone(2));
this.zones.Add(new Zone(42));
// Add coord to 2th zones
this.zones[0].AddCoord(1);
Console.WriteLine("Count : " + this.zones[0].coords.Count); // -> Count: 1
// Now with bool - NOT WORKING
this.zones[0].SetBool();
Console.WriteLine("Bool: " + this.zones[0].isOnChunkBorder ); // -> Bool: False
// Now with bool - WORKING
this.zones[0] = this.zones[0].SetBoolAndReturnThis();
Console.WriteLine("Bool: " + this.zones[0].isOnChunkBorder ); // -> Bool: True
}
public struct Zone {
public bool isOnChunkBorder;
public List<int> coords;
public Zone(int firstCoord) {
this.coords = new List<int>();
this.coords.Add(firstCoord);
this.isOnChunkBorder = false;
}
public void AddCoord(int coord) {
this.coords.Add(coord);
}
public void SetBool() {
this.isOnChunkBorder = true;
}
public Zone SetBoolAndReturnThis() {
this.isOnChunkBorder = true;
return this;
}
}
}
I don't know why struct boolean are not updated when I'm using a simple update, but works fine is Zone is replaced by Class or if the struct is returned ?
The effect you observe caused by the Zone being a struct.
Structs are value types and are copied on assignment.
Related
I have two classes:
public class Stats : MonoBehaviour
{
// Primary Stats
public int strength;
public int agility;
public int intellect;
public int stamina;
public int spirit;
}
and
public class EquipmentProperties : ItemProperties
{
public Stats stats;
}
public enum Stats
{//variables from "Stats" class to be in this enum
}
I am trying to get all the variables from the Stats class to be in the stats enum without having to manually enter them..
"I am trying to get all the variables from the Stats class to be in the stats enum without having to manually enter them"
Enums must be specified at compile time, you can't dynamically add enums during run-time. If you would like to stablish the fields of your enum dynamically with your class variables, guess that because the Stats class might change along the app's development, you would need to store that enum somewhere, because if not you would need to access the fields of the dynamic enum according to that generic way of setting the enumeration, in a kind of meta-programming templated way that would not make much sense.
So along with your question comes the question of how to store that enum to be used afterwards I guess. For that you can check EnumBuilder class.
Extending that example, you can build the enum according to the specific Stats class like this:
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
public class Stats
{
// Primary Stats
public int strength;
public int agility;
public int intellect;
public int stamina;
public int spirit;
}
class Example
{
public static List<string> getFields(Type type) {
var propertyValues = type.GetFields();
var result = new Stats[propertyValues.Length];
var retStr = new List<string>();
for (int i = 0; i < propertyValues.Length; i++) {
retStr.Add(propertyValues[i].Name);
}
return retStr;
}
public static void Main() {
// Get the current application domain for the current thread.
AppDomain currentDomain = AppDomain.CurrentDomain;
// Create a dynamic assembly in the current application domain,
// and allow it to be executed and saved to disk.
AssemblyName aName = new AssemblyName("TempAssembly");
AssemblyBuilder ab = currentDomain.DefineDynamicAssembly(
aName, AssemblyBuilderAccess.RunAndSave);
// Define a dynamic module in "TempAssembly" assembly. For a single-
// module assembly, the module has the same name as the assembly.
ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");
// Define a public enumeration with the name "Elevation" and an
// underlying type of Integer.
EnumBuilder eb = mb.DefineEnum("Stats", TypeAttributes.Public, typeof(int));
int fieldCount = 0;
getProperties(typeof(Stats)).ForEach(field => {
eb.DefineLiteral(field, fieldCount);
fieldCount++;
});
// Define two members, "High" and "Low".
//eb.DefineLiteral("Low", 0);
//eb.DefineLiteral("High", 1);
// Create the type and save the assembly.
Type finished = eb.CreateType();
ab.Save(aName.Name + ".dll");
foreach (object o in Enum.GetValues(finished)) {
Console.WriteLine("{0}.{1} = {2}", finished, o, ((int)o));
}
Console.ReadLine();
}
}
Output:
Stats.strength = 0
Stats.agility = 1
Stats.intellect = 2
Stats.stamina = 3
Stats.spirit = 4
Prolog
This is of course not what you are asking directly since it is not automatic but I would suggest a Dictionary<Stats, int> and do e.g.
public class StatsComponent : MonoBehaviour
{
// Make these only assignable via the Inspector
[SerializeField] private int strength;
[SerializeField] private int agility;
[SerializeField] private int intellect;
[SerializeField] private int stamina;
[SerializeField] private int spirit;
public readonly Dictionary<Stats, int> stats = new Dictionary<Stats, int>();
private void Awake ()
{
// Initialize once with values from the Inspector
stats.Add(Stats.Strength, strength);
stats.Add(Stats.Agility, agility);
stats.Add(Stats.Intellect, intellect);
stats.Add(Stats.Stamina, stamina);
stats.Add(Stats.Spirit, spirit);
}
}
public enum Stats
{
Strength,
Agility,
Intellect,
Stamina,
Spirit
}
Of course there are ways to automatize that via reflection but I'm sure it will bring you more headaches and issues then it is solving - that's only an opinion of course.
Intermediate Solution
If you don't want to type things twice you could instead of an enum rather go by index or strings e.g. using SerializedDictionary you could simply have a
public SerializedDictionary<string, int> stats;
and fill it in the Inspector and not have your fields at all.
Enum Generator Window
However, if you still want at least automation with a minimal effort to build on top of this answer I made this a tool EditorWindow you can directly use within Unity.
Just place this script anywhere in your project.
#if UNITY_EDITOR
using System;
using System.IO;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine;
public class EnumGeneratorWindow : EditorWindow
{
// This is of course optional but I thought it makes sense to filer for a specific field type
private enum FieldType
{
Int,
Float,
Bool,
// more could of course be added
}
private MonoScript sourceScript;
private MonoScript targetScript;
private FieldType fieldType;
private Type GetFieldType()
{
return fieldType switch
{
FieldType.Int => typeof(int),
FieldType.Float => typeof(float),
FieldType.Bool => typeof(bool),
// according to the enum add more cases
_ => null
};
}
[MenuItem("Window/ENUM GENERATOR")]
private static void Init()
{
var window = GetWindow<EnumGeneratorWindow>();
window.Show();
}
private void OnGUI()
{
EditorGUILayout.LabelField("ENUM GENERATOR", EditorStyles.boldLabel);
sourceScript = EditorGUILayout.ObjectField("Source", sourceScript, typeof(MonoScript), false) as MonoScript;
if (!sourceScript)
{
EditorGUILayout.HelpBox("Reference the script where to fetch the fields from", MessageType.None, true);
return;
}
var sourceType = sourceScript.GetClass();
if (sourceType == null)
{
EditorGUILayout.HelpBox("Could not get Type from source file!", MessageType.Error, true);
return;
}
targetScript = EditorGUILayout.ObjectField("Target", targetScript, typeof(MonoScript), false) as MonoScript;
if (!targetScript)
{
EditorGUILayout.HelpBox("Reference the script where write the generated enum to", MessageType.None, true);
return;
}
if (targetScript == sourceScript)
{
EditorGUILayout.HelpBox("The source and target script should probably rather not be the same file ;)", MessageType.Error, true);
return;
}
var targetType = targetScript.GetClass();
if (targetType == null)
{
EditorGUILayout.HelpBox("Could not get Type from target file!", MessageType.Error, true);
return;
}
fieldType = (FieldType)EditorGUILayout.EnumPopup("Field Type", fieldType);
EditorGUILayout.Space();
EditorGUILayout.LabelField("Preview", EditorStyles.boldLabel);
var fields = sourceType.GetFields().Where(f => f.FieldType == GetFieldType()).Select(f => f.Name).ToArray();
var fileContent = new StringBuilder("public enum ").Append(targetType.Name).Append(" { ");
for (var i = 0; i < fields.Length; i++)
{
if (i != 0)
{
fileContent.Append(", ");
}
fileContent.Append(fields[i]);
}
fileContent.Append(" }");
EditorGUILayout.LabelField(fileContent.ToString());
var color = GUI.color;
GUI.color = Color.red;
GUILayout.BeginVertical();
{
EditorGUILayout.LabelField("! DANGER ZONE !", EditorStyles.boldLabel);
EditorGUILayout.Space();
if (GUILayout.Button("GENERATE ENUM"))
{
var targetID = targetScript.GetInstanceID();
// e.g. Assets/SomeFolder/MyStats.cs
var targetAssetPath = AssetDatabase.GetAssetPath(targetID);
// just as a safety net
if (EditorUtility.DisplayDialog("Generate and overwrite with enum?", $"Attention\n\nThis will overwrite any content of {targetAssetPath} with the new content.\n\nAre you sure?", "Yes generate", "OMG NO! Cancel this!"))
{
// a bit of a hack but we need to convert the Unity asset path into a valid system path by erasing one duplicate "Assets"
var pathParts = targetAssetPath.Split('/').ToArray();
// overwrite the "Assets" with the full path to Assets
pathParts[0] = Application.dataPath;
// re-combine all path parts but this time use the according system file path separator char
var targetSystemPath = Path.Combine(pathParts);
// Write the content into the file via the normal file IO
File.WriteAllText(targetSystemPath, fileContent.ToString());
// trigger a refresh so unity re-loads and re-compiles
AssetDatabase.Refresh();
}
}
}
GUILayout.EndVertical();
GUI.color = color;
}
}
#endif
How it works:
Open the window via the header menu -> Window -> ENUM GENERATOR
Drag in your MonoBehaviour script into "Source"
Create a new empty script with the enum name you like
Drag your enum target script into "Target"
Select the type of fields we are looking for
Finally hit generate
Here is a little demo ;)
I just start of using Example.cs
public class Example : MonoBehaviour
{
public int someInt, anotherInt;
public float someFloat, anotherFloat, andOnMore;
public bool someBool, yetAnotherBool;
}
and ExampleEnum.cs
public enum ExampleEnum
{
}
So i wanted to store categories of data within my "player" class with static classes so that they are named variables and are callable by name. I recently found a solution for calling variables within a class by their string name to get and set them here: C# setting/getting the class properties by string name and i tried to call the static class via string by using "Type.GetType(pattern)": Get class by string value
I attempted to modify the object to also call the static class by a string but I am missing something because get and set doesn't work at all:
public class Player
{
//categories of variables within static classes
public static class Status { public static int health = 10, stamina = 10, mana = 10; };
public static class Immunity { public static bool fire = false, water = false, giantEnemyCrab = true; };
//paralell arrays
public string[] namelistStatus = { "health", "stamina", "mana" };
public string[] namelistImmunity = { "fire", "water", "giantEnemyCrab" };
//get and set Variables from nested classes
//('classname' is the name of the class,'propertyName' is the name of the variable)
public object this[string className, string propertyName]
{
//indirectly calls variables within static classes entirely via string
get
{
//i think the problem originates from "Type.GetType(className)" not being the correct way to call the static class by their string name
Type myType = Type.GetType(className);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
return myPropInfo.GetValue(this, null);
}
set
{
Type myType = Type.GetType(className);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
myPropInfo.SetValue(this, value, null);
}
}
//display variables
public void DisplayPlayerStatus()
{
for (int i = 0; i < namelistStatus.Length; i++)
{
Console.WriteLine(namelistStatus[i]+":"+this["Status", namelistStatus[i]]);
}
for (int i = 0; i < namelistStatus.Length; i++)
{
if (Convert.ToBoolean(this["Immunity", namelistStatus[i]]))
{
Console.WriteLine(namelistStatus[i] + " Immunity");
}
}
}
}
That was a simplification of the Player class I'm trying to organize with nested static classes, there are also some functions that are meant to set the variables in the status and immunity classes but here i only made an example function for 'getting' the nested static class variables via string but 'setting' doesn't work either.
Any suggestions of how i would be able to do this properly would be much appreciated.
Problems:
Your static inner classes are just that - nested Types inside your Player class - not properties of your Player class.
Your properties inside your static class are actually Fields.
You used the wrong name list for Immunities inside Player.DisplayPlayerStatus()
You could ( but you really should NOT , reconsider your design ) fix it like this
public class Player
{
public string[] namelistImmunity = { "fire", "water", "giantEnemyCrab" };
public string[] namelistStatus = { "health", "stamina", "mana" };
public object this[string className, string propertyName]
{
//indirectly calls variables within static classes entirely via string
get
{
var innerClass = GetType().GetNestedType(className);
var myFieldInfo = innerClass?.GetField(propertyName);
return myFieldInfo.GetValue(null);
}
set
{
var innerClass = GetType().GetNestedType(className);
var myFieldInfo = innerClass?.GetField(propertyName);
myFieldInfo?.SetValue(null, value);
}
}
public void DisplayPlayerStatus()
{
// why for and indexing - foreach is far easier
foreach (var s in namelistStatus)
Console.WriteLine(s + ":" + this["Status", s]);
// you used the wrong list of names here
foreach (var n in namelistImmunity)
if (Convert.ToBoolean(this["Immunity", n]))
Console.WriteLine(n + " Immunity");
}
public static class Immunity
{
// these are fields
public static bool fire = false,
water = false,
giantEnemyCrab = true;
};
public static class Status
{
// fields as well
public static int health = 10,
stamina = 10,
mana = 10;
};
}
Tested with:
using System;
internal class Program
{
public static void Main(string[] args)
{
Player p = new Player();
p.DisplayPlayerStatus();
Console.WriteLine();
p["Status", "health"] = 200;
p.DisplayPlayerStatus();
Console.ReadLine();
}
// the fixed stuff goes here
}
Output:
health:10
stamina:10
mana:10
giantEnemyCrab Immunity
health:200
stamina:10
mana:10
giantEnemyCrab Immunity
Your classes are currently very tighty coupled, if you add psyonicPower to your stats, you need to edit your Player, edit Player.Status, modify Player.namelistStatus.
You could autodiscover the static class fieldnames via reflection in a similar fashion like you access the field-values and get rid of both your namelistXXXX - but still, the design is bad.
I am trying to copy a part of an array to a different location. Here is the declaration.
public ObjectBasicFeatures[] ALLOBJECTS = new ObjectBasicFeatures[150];
When I do this,
ALLOBJECTS[1]= ALLOBJECTS[0];
Any changes made to either one cause a change in the other one.
From what I understand it is setting the pointers to the same address (Which is 'copying' it, but not what I want).
How can I copy the memory stored at pointer ALLOBJECTS[0] to ALLOBJECTS[1]?
Things tried:
Array.Copy() (Still copied the pointers...)
Using the dereference operator (Didn't work...)
You need a copy constructor or make ObjectBasicFeatures a struct (struct is value type whereas class is a reference type)
Then you could write:
ALLOBJECTS[1]= new ObjectBasicFeatures(ALLOBJECTS[0]);
Another Example:
class Program
{
static void Main(string[] args)
{
var o1 = new ObjectBasicFeatures();
var o2 = new ObjectBasicFeatures(o1);
System.Diagnostics.Debug.Assert(!o1.Equals(o2));
}
}
public class ObjectBasicFeatures
{
public ObjectBasicFeatures()
{
MyProperty = 0;
}
/// <summary>
/// copy constructor
/// </summary>
/// <param name="other"></param>
public ObjectBasicFeatures(ObjectBasicFeatures other)
{
MyProperty = other.MyProperty;
}
public int MyProperty { get; set; }
}
To achieve this you need to create a constructor which takes input as its object and copies its values. But here is a catch. You need to do the same for all the classes you refer in ObjectBasicFeatures class and so on till the leaf node. Below is a piece of code I tested with.
Please no the value of member (direct member of class) does not reflect in other(copied) element but the value of level2.member is updated in both the objects when you change it in one object
class Program
{
static void Main(string[] args)
{
ObjectBasicFeatures[] ALLOBJECTS = new ObjectBasicFeatures[3];
ALLOBJECTS[0] = new ObjectBasicFeatures("zero");
ALLOBJECTS[1] = new ObjectBasicFeatures("one");
ALLOBJECTS[2] = new ObjectBasicFeatures("two");
ALLOBJECTS[1] = new ObjectBasicFeatures(ALLOBJECTS[0]);
ALLOBJECTS[0].member = "Updated Value";
ALLOBJECTS[0].level2Member.member = "Updated Level 2 Value";
Console.WriteLine("At index 0 : " + ALLOBJECTS[0].member + ", Level2 : " + ALLOBJECTS[0].level2Member.member);
Console.WriteLine("At index 1 : " + ALLOBJECTS[1].member + ", Level2 : " + ALLOBJECTS[1].level2Member.member);
Console.ReadKey();
}
}
public class ObjectBasicFeatures
{
public string member;
public Level2 level2Member; // This is to demonstrate that it will be updated in both the objects
public ObjectBasicFeatures(string memberVal)
{
member = memberVal;
level2Member = new Level2("Level 2 Value");
}
/// Constructor to copy member values.
public ObjectBasicFeatures(ObjectBasicFeatures originalObject)
{
member = originalObject.member;
level2Member = originalObject.level2Member;
}
}
/// This class does not have a constructor to copy member values.
public class Level2
{
public string member;
public Level2(string memberVal)
{
member = memberVal;
}
}
Output of this will look like below
ALLOBJECTS[1]= new ObjectBasicFeatures {
PropertyName1=ALLOBJECTS[0].PropertyName1
PropertyName2=ALLOBJECTS[0].PropertyName2
}
Hope this helps.
If your Class ObjectBasicFeatures has complex properties you should consider deep copy function
I want to add row number in object list.
here's the they i do it now but there must be better way
Profile for mapping
public class VendorEnquiryDM_TO_VM : Profile
{
public VendorEnquiryDM_TO_VM()
{
CreateMap<VENDORENQUIRY, VendorEnquiryVM>();
}
}
public class VendorEnquiryVM_TO_DM : Profile
{
public VendorEnquiryVM_TO_DM()
{
CreateMap<VENDOR_ENQUIRY, VendorEnquiryVM>().ReverseMap();
}
}
Register profile
cfg.AddProfile<VendorEnquiryDM_TO_VM>();
cfg.AddProfile<VendorEnquiryVM_TO_DM>();
This is how I add sno.
alldata = Mapper.Map<IEnumerable<Vendor_EnquiryVM>>(objDAO.getVendorEnquiry());
var _roles = alldata.Select((t, index) => new Vendor_EnquiryVM
{
sno = index + 1,
CONTACT_NO=t.CONTACT_NO,
DATE=t.DATE,
EMAIL=t.EMAIL,
id=t.id,
FIRST_NAME=t.FIRST_NAME,
wer=t.wer,
asdf=t.asdf
});
Due to just one serial no. I need to assign all properties and this is somewhat fraustrating to me for large model, please suggest me better way of doing this.
You can define a static Id and when you create the class, increment it by one
here how your class code should look like
public class Test
{
private static int mId = 0;
public Test()
{
mId = mId +1;
}
public int Id
{
get{ return mId;}
}
}
Here a demo
in order to use the same idea with collections like List, I applied some modifications and here what you can do
public class Test
{
private static int mIndex = 0; // this parameter will be incremented for each new Test
private int mId =0; // this parameter will hold the last incremented value
public Test()
{
mId = ++mIndex; // mIndex++ if you want to start with 0
}
public int Id
{
get{ return mId;}
}
}
Demo with lists
hope this will help you
I want to do an application that pareses text. So far, I have a class called Result, that holds the value and type each part of an equation.
public enum ResultType
{
Int32,
Double,
Boolean,
Color,
DateTime,
String,
Undefined,
Void
}
public class Result
{
public object Value { get; set; }
public ResultType Type { get; set; }
}
Possible Result's could be:
5 : Int32
true : Boolean
DADACC : Color
"Hello World!" : String
10.0 : Double
13/11/1986 : DateTime
Now I want to sum/divide/pow/... two Results but I really don´t want to do all the work. In C#, you can mix them all together and get an answer.
var value = "Hello" + 2.0 + 4 + DateTime.Today; (value = "Hello2413/09/2011 12:00:00 a.m.")
Is there an easy way to handle this? Or do I have to figure out all combos by myself? I´m thinking about something like:
var Operator = "+"; // or "-","*","/","^","%"
var sum = DoTheCSharpOperation(Operator, ResultA.Value, ResultB.Value)
var sumResult = new Result(sum);
This sounds to me like a perfect application for the "dynamic" keyword:
using System;
using System.Diagnostics;
namespace ConsoleApplication33 {
public static class Program {
private static void Main() {
var result1=DoTheCSharpOperation(Operator.Plus, 1.2, 2.4);
var result2=DoTheCSharpOperation(Operator.Plus, "Hello", 2.4);
var result3=DoTheCSharpOperation(Operator.Minus, 5, 2);
Debug.WriteLine(result1); //a double with value 3.6
Debug.WriteLine(result2); //a string with value "Hello2.4"
Debug.WriteLine(result3); //an int with value 3
}
public enum Operator {
Plus,
Minus
}
public static object DoTheCSharpOperation(Operator op, dynamic a, dynamic b) {
switch(op) {
case Operator.Plus:
return a+b;
case Operator.Minus:
return a-b;
default:
throw new Exception("unknown operator "+op);
}
}
}
}