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
Related
I'm trying to learn how the lists work and I'm quite lost on a concept of using set; get; properties and working with a List. I have a project that I want to populate a list with 2 items that are related to each other (hence a object) Relation and an ID so I created a RelationLink class, the idea is to populate list with these 2 prosperities but using (get; set;) and I'm not quite sure how to do this so it would let me add the properties to a list and retrive a list from a PropertiesRepository as well.
public class PropertiesRepository
{
public class RelationLink
{
public string Relation { get; set; }
public string LinkID { get; set; }
}
public class ListofRelations
{
public List<RelationLink> relList { get; set; }
public void addRelation(RelationLink rel)
{
relList.Add(rel);
}
}
}
the code below fails at listofRelations.addRelation(relationLink) when debugging I can see that its going to add addRelation method and I see the values being passed. However when adding the object to a list nothing is being added. so when get runs it fails due to null exception.
am I doing the setters getters correctly? the part where I'm lost is how can I add the 2 (string) properties to that list in a main program file with setters, that could be read from relList
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
PropertiesRepository repProperties = new PropertiesRepository();
PropertiesRepository.RelationLink relationLink = new PropertiesRepository.RelationLink();
PropertiesRepository.ListofRelations listofRelations = new PropertiesRepository.ListofRelations();
relationLink.Relation = "Relation A";
relationLink.LinkID = "12345";
listofRelations.addRelation(relationLink);
foreach (var elm in listofRelations.relList)
{
Console.WriteLine("Relation from List is " + elm.Relation + "Link ID from List is " + elm.LinkID);
}
}
}
relList in your instance of listofRelations is never initialised with an instance of the list.
public class ListofRelations
{
public List<RelationLink> relList { get; set; } = new List<RelationLink>();
public void addRelation(RelationLink rel)
{
relList.Add(rel);
}
}
you could initialise it like this or in a constructor. Or before you call addRelation you could write if you want.
listOfRelations.relList = new List<RelationLink>();
Consider the following code snippet that does not compile.
class Class
{
public double Value { get; set; }
public int Frequency { get; set; }
}
class BoxAndWhisker
{
private readonly List<Class> _classes = new List<Class>();
public BoxAndWhisker()
{
Classes = _classes.AsReadOnly();
}
public IReadOnlyList<Class> Classes { get; }
}
class Program
{
static void Main(string[] args)
{
BoxAndWhisker baw = new BoxAndWhisker
{
Classes =
{
new Class{ Value=1,Frequency=20},
new Class{Value=2,Frequency=10}
}
};
}
}
I want the property Classes to be read only right after baw is instatiated. How to do so? In other words, Classes must be writable in object initializer but read only in other places.
Edit
I prefer object initializer to parameterized constructor.
Why not pass Classes via constructor? E.g.
class BoxAndWhisker {
public BoxAndWhisker(params Class[] items) {
Classes = null != items
? new List<Class>(items).AsReadOnly()
: throw new ArgumentNullException(nameof(items));
}
public IReadOnlyList<Class> Classes { get; }
}
Then
static void Main(string[] args)
{
BoxAndWhisker baw = new BoxAndWhisker(
new Class { Value = 1, Frequency = 20 },
new Class { Value = 2, Frequency = 10 }
);
...
}
Remove the
set;
From the properties within
Class
And make the Class have a Constructor which sets the initial values of the Properties, therefore they cannot be overwrote / changed
The "object initializer" syntax in C# has no semantic difference compared to a property value assignment.
You can read in the docs:
The object initializers syntax allows you to create an instance, and after that it assigns the newly created object, with its assigned properties, to the variable in the assignment.
So this:
var foo = new Bar { Baz = "baz" };
is completely equivalent to:
var temp = new Bar();
temp.Baz = "baz";
var foo = temp;
So you cannot restrict the property assignment the way you want.
The only solution is to use a constructor as proposed in the other answers.
You pass the IList<Class> instance to the BoxAndWhisker constructor and maintain a backing IReadOnlyList<Class> property
class BoxAndWhisker
{
public BoxAndWhisker(IList<Class> classes)
{
if (classes == null)
throw new ArgumentNullException(nameof(classes));
Classes = new ReadOnlyCollection<Class>(classes);
}
public IReadOnlyList<Class> Classes { get; }
}
The usage example
BoxAndWhisker baw = new BoxAndWhisker(new List<Class>
{
new Class {Value = 1, Frequency = 20},
new Class {Value = 2, Frequency = 10}
});
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.
So I'm making a game, and it saves users' progress on the computer in a binary file. The User class stores a few things:
Integers for stat values (Serializable)
Strings for the Username and the skin assets
Lists of both the Achievement class and the InventoryItem class, which I have created myself.
Here are the User fields:
public string Username = "";
// ID is used for local identification, as usernames can be changed.
public int ID;
public int Coins = 0;
public List<Achievement> AchievementsCompleted = new List<Achievement>();
public List<InventoryItem> Inventory = new List<InventoryItem>();
public List<string> Skins = new List<string>();
public string CurrentSkinAsset { get; set; }
The Achievement class stores ints, bools, and strings, which are all serializable. The InventoryItem class stores its name (a string) and an InventoryAction, which is a delegate that is called when the item is used.
These are the Achievement class's fields:
public int ID = 0;
public string Name = "";
public bool Earned = false;
public string Description = "";
public string Image;
public AchievmentDifficulty Difficulty;
public int CoinsOnCompletion = 0;
public AchievementMethod OnCompletion;
public AchievementCriteria CompletionCriteria;
public bool Completed = false;
And here are the fields for the InventoryItem class:
InventoryAction actionWhenUsed;
public string Name;
public string AssetName;
The source of the InventoryAction variables are in my XNAGame class. What I mean by this is that the XNAGame class has a method called "UseSword()" or whatever, which it passes into the InventoryItem class. Previously, the methods were stored in the Game1 class, but the Game class, which Game1 inherits from, is not serializable, and there's no way for me to control that. This is why I have an XNAGame class.
I get an error when trying to serialize: "The 'SpriteFont' class is not marked as serializable", or something like that. Well, there is a SpriteFont object in my XNAGame class, and some quick tests showed that this is the source of the issue. Well, I have no control over whether or not the SpriteFont class is Serializable.
Why is the game doing this? Why must all the fields in the XNAGame class be serializable, when all I need is a few methods?
Keep in mind when answering that I'm 13, and may not understand all the terms you're using. If you need any code samples, I'll be glad to provide them for you. Thanks in advance!
EDIT: One solution I have thought of is to store the InventoryAction delegates in a Dictionary, except that this will be a pain and isn't very good programming practice. If this is the only way, I'll accept it, though (Honestly at this point I think this is the best solution).
EDIT 2: Here's the code for the User.Serialize method (I know what I'm doing in inefficient, and I should use a database, blah, blah, blah. I'm fine with what I'm doing now, so bear with me.):
FileStream fileStream = null;
List<User> users;
BinaryFormatter binaryFormatter = new BinaryFormatter();
try
{
if (File.Exists(FILE_PATH) && !IsFileLocked(FILE_PATH))
{
fileStream = File.Open(FILE_PATH, FileMode.Open);
users = (List<User>)binaryFormatter.Deserialize(fileStream);
}
else
{
fileStream = File.Create(FILE_PATH);
users = new List<User>();
}
for (int i = 0; i < users.Count; i++)
{
if (users[i].ID == this.ID)
{
users.Remove(users[i]);
}
}
foreach (Achievement a in AchievementsCompleted)
{
if (a.CompletionCriteria != null)
{
a.CompletionCriteria = null;
}
if (a.OnCompletion != null)
{
a.OnCompletion = null;
}
}
users.Add(this);
fileStream.Position = 0;
binaryFormatter.Serialize(fileStream, users);
You cannot serialize a SpriteFont by design, actually this is possible (.XNB file) but it hasn't been made public.
Solution:
Strip it off your serialized class.
Alternatives:
If for some reasons you must serialize some font, the first thing that comes to my mind would be to roll-out your own font system such as BMFont but that's a daunting task since you'll have to use it everywhere else where you might already do ...
Generate a pre-defined amount of fonts (i.e. Arial/Times/Courier at size 10/11/12 etc ...) using XNA Content app (can't recall its exact name); then store this user preference as two strings. With a string.Format(...) you should be able to load the right font back quite easily.
Alternative 2 is certainly the easiest and won't take more than a few minutes to roll-out.
EDIT
Basically, instead of saving a delegate I do the following:
inventory items have their own type
each type name is de/serialized accordingly
their logic does not happen in the main game class anymore
you don't have to manually match item type / action method
So while you'll end up with more classes, you have concerns separated and you can keep your main loop clean and relatively generic.
Code:
public static class Demo
{
public static void DemoCode()
{
// create new profile
var profile = new UserProfile
{
Name = "Bill",
Gold = 1000000,
Achievements = new List<Achievement>(new[]
{
Achievement.Warrior
}),
Inventory = new Inventory(new[]
{
new FireSpell()
})
};
// save it
using (var stream = File.Create("profile.bin"))
{
var formatter = new BinaryFormatter();
formatter.Serialize(stream, profile);
}
// load it
using (var stream = File.OpenRead("profile.bin"))
{
var formatter = new BinaryFormatter();
var deserialize = formatter.Deserialize(stream);
var userProfile = (UserProfile) deserialize;
// set everything on fire :)
var fireSpell = userProfile.Inventory.Items.OfType<FireSpell>().FirstOrDefault();
if (fireSpell != null) fireSpell.Execute("whatever");
}
}
}
[Serializable]
public sealed class UserProfile
{
public string Name { get; set; }
public int Gold { get; set; }
public List<Achievement> Achievements { get; set; }
public Inventory Inventory { get; set; }
}
public enum Achievement
{
Warrior
}
[Serializable]
public sealed class Inventory : ISerializable
{
public Inventory() // for serialization
{
}
public Inventory(SerializationInfo info, StreamingContext context) // for serialization
{
var value = (string) info.GetValue("Items", typeof(string));
var strings = value.Split(';');
var items = strings.Select(s =>
{
var type = Type.GetType(s);
if (type == null) throw new ArgumentNullException(nameof(type));
var instance = Activator.CreateInstance(type);
var item = instance as InventoryItem;
return item;
}).ToArray();
Items = new List<InventoryItem>(items);
}
public Inventory(IEnumerable<InventoryItem> items)
{
if (items == null) throw new ArgumentNullException(nameof(items));
Items = new List<InventoryItem>(items);
}
public List<InventoryItem> Items { get; }
#region ISerializable Members
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
var strings = Items.Select(s => s.GetType().AssemblyQualifiedName).ToArray();
var value = string.Join(";", strings);
info.AddValue("Items", value);
}
#endregion
}
public abstract class InventoryItem
{
public abstract void Execute(params object[] objects);
}
public abstract class Spell : InventoryItem
{
}
public sealed class FireSpell : Spell
{
public override void Execute(params object[] objects)
{
// using 'params object[]' a simple and generic way to pass things if any, i.e.
// var world = objects[0];
// var strength = objects[1];
// now do something with these !
}
}
Okay, so I figured it out.
The best solution was to use a Dictionary in the XNAGame class, which stores two things: an ItemType (an enumeration), and an InventoryAction. Basically, when I use an item, I check it's type and then look up it's method. Thanks to everyone who tried, and I'm sorry if the question was confusing.
Hello I'm trying to retrun array type named ZverejnenyUcetType but the issue is that this array might contain two types : StandartniUcetType and NestandardniUcetType.
So the issue is when I try to return the array like this:
string[] dic_vstup = new string[] { (line) };
RozhraniWSDL.InformaceOPlatciType[] dic_vystup;
RozhraniWSDL.rozhraniCRPDPH srv = new RozhraniWSDL.rozhraniCRPDPH();
StatusType status = srv.getStatusNespolehlivyPlatce(dic_vstup, out dic_vystup);
string abc = status.bezVypisuUctu.ToString(); // If it is already a string, then ToString not needed
for (int i = 0; i < dic_vystup.Length; i++)
{
RozhraniWSDL.InformaceOPlatciType info = dic_vystup[i];
for (int x = 0; x <= 3; x++)
{
file2.WriteLine((((RozhraniWSDL.StandardniUcetType)(info.zverejneneUcty[x].Item)).cislo) + "-"
+ (((RozhraniWSDL.StandardniUcetType)(info.zverejneneUcty[x].Item)).cislo) + "/"
+ (((RozhraniWSDL.StandardniUcetType)(info.zverejneneUcty[x].Item)).kodBanky));
}}
I get following exception: unable to cast object of type RozhraniWSDL.NestandardniUcetType to type RozhraniWSDL.StandardniUcetType.
NestandardniUcetType contains only one item - cislo
StandartníUcetType have 3 items- predcislo, cislo, kod banky
Here is an image of the array:
I thought that the solution might be to determinate which of the result are of type StandartniUcetType and which are NestandardniUcetType.
I would like to ask if this is possible to do?
I found this solution more common.
Thank you for your time.
If the array has two different types, you could add an if statement, like this:
if (info.zverejneneUcty[x].Item is RozhraniWSDL.StandardniUcetType) {
...
} else {
...
}
A slightly better approach would be to cast using the as operator, like this:
RozhraniWSDL.StandardniUcetType std = info.zverejneneUcty[x].Item as RozhraniWSDL.StandardniUcetType;
if (std != null) {
...
}
RozhraniWSDL.NestandardniUcetType nstd = info.zverejneneUcty[x].Item as RozhraniWSDL.NestandardniUcetType;
if (nstd != null) {
...
}
Finally, a very good approach would be writing two separate methods for the two types, and using dynamic to perform a dispatch. To do that, define two functions, like this:
static void WriteToFile(RozhraniWSDL.StandardniUcetType std, StreamWriter file) {
...
}
static void WriteToFile(RozhraniWSDL.NestandardniUcetType nstd, StreamWriter file) {
...
}
Now change your loop as follows:
for (int x = 0; x <= 3; x++) {
dynamic item = info.zverejneneUcty[x].Item;
WriteToFile(item, file2); // <<== Magic
}
Using the OfType extension method over the array will filter for the type you need
foreach (var item in info.zverejneneUcty.OfType<RozhraniWSDL.StandardniUcetType>())
{
file2.WriteLine(item.predcislo + "-" + item.cislo + "-" + item.kodBanky);
}
I'd redesign the types and remove the issue instead, through an abstract class, like this:
// I'm making up the inner types, adapt this to your code
public abstract class UcetType
{
public virtual object predcislo { get; set; }
public virtual object cislo { get; set; }
public virtual object kodBanky { get; set; }
public virtual void WriteToFile(StreamWriter file)
{
// build the string and write it to the file
// considering all properties
// this acts as "default" for this type and all derived ones
}
}
public class StandardniUcetType : UcetType
{
// This will use the abstract as-is
// with all 3 properties and the "default" WriteToFile() method
}
public class NestandardniUcetType : UcetType
{
/// <summary>
/// Attempting to use this will throw an exception
/// </summary>
public override object predcislo
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
/// <summary>
/// Attempting to use this will throw an exception
/// </summary>
public override object kodBanky
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
// change the way WriteToFile behaves
public override void WriteToFile(StreamWriter file)
{
// build the string and write it to the file
// only considering 'cislo' property
}
}
// Usage example, based on question
for (int i = 0; i < dic_vystup.Length; i++)
{
RozhraniWSDL.InformaceOPlatciType info = dic_vystup[i];
// I assume "3" is the expected length of the array ? Change the for like this:
for (int x = 0; x <= info.zverejneneUcty.Length; x++)
{
//Delegate to the WriteToFile() method the task to build and write the line!
info.zverejneneUcty[x].Item.WriteToFile(file2);
}
}
I see no benefit in a dynamic approach here. This is more readable and easy to expand in the future (need a new type ? just derive UcetType in a new class and override away).