C# Access Struct using String - c#

I am a bit stuck with my game. I have a class called Upgradebuttons. From this class I want to access some variables stored in a struct from another class. I can easily access the variables by typing classname.structname.preferedvar but the structname depends on which upgrade as been clicked. So I want to call the struct using a string. I have tried:
MethodInfo method = typeof(Classname).GetMethod(structname);
But this only works if it is a void and not a struct. What do I need to do in order to get this working?
public class UpgradeButtons : MonoBehaviour {
public void somefunction{
// here i want to have access
}
}
This is an example of the class I want to have access to:
public class Upgrades: MonoBehaviour {
public struct Upgrade1{
public const int Cost = 10;
public const float Value = 0.1f;
public static string Naam = "Autoclicker";
}
}

While this is possible, it sounds like poorly thought out design. Perhaps you could use one common struct Upgrade and use the Name property to find it at runtime?
Example:
public struct Upgrade
{
public string Name;
public int Cost;
public float Value;
public Upgrade(string name, int cost, float value)
{
this.Name = name;
this.Cost = cost;
this.Value = value;
}
}
public class UpgradeButtons : MonoBehavior
{
List<Upgrade> Upgrades = new List<Upgrade>();
public void CreateButtons()
{
Upgrades.Add(new Upgrade("Autoclicker", 10, 0.1f));
//etc...
}
public void somefunction()
{
Upgrade autoclickUpgrade = Upgrades.Where(p => p.Name == "Autoclicker").FirstOrDefault();
if(autoclickUpgrade == null)
throw new Exception("Could not find Autoclicker upgrade.");
//do something with autoclickUpgrade
}
}

just remove static from string Naam:
public class Upgrades: MonoBehaviour {
public struct Upgrade1{
public const int Cost = 10;
public const float Value = 0.1f;
public string Naam = "Autoclicker";
}
}
When an object ( class, variable, method) is defined as static it can not be referenced through an instance.

If I understand your question, you are on the right track, probably. Since the struct (type) that your add-on depends on may or may not exist, Reflection is the best way to go here.
Try Assembly.GetType(), or a related method, to attempt to load the type, check its existence, and iterate its members.
http://msdn.microsoft.com/en-us/library/y0cd10tb(v=vs.110).aspx

Related

Assigning to a variable by reference?

Thanks to the kind folks who answered my previous question from a few days ago, I now know how to pass arguments by reference:
static void Main()
{
int i = 0;
Add(ref i, 100);
// now i == 100
}
static void Add(ref int arg, int increment)
{
arg += increment;
}
But is there a way for me not to just pass i by reference, but actually store its location in another variable? By that I mean use i like I did in my example; affecting the original instance, but in a way that's permanently linked and not leaving scope.
I vaguely know that I could use a pointer to determine the location in unsafe context but I was wondering if I could do this without any of that, or if it is just recommended to use the unsafe method.
If you are using C# 7 you can use ref local and ref return to store an updateable reference to any field.
In this example I change the private field _privateField from 0 to 100 from outside Foo, the class in which it is defined, by returning it as a ref int and updating it by reference.
class Foo
{
private int _privateField = 0;
public ref int GetReference()
{
return ref _privateField;
}
public override string ToString()
{
return _privateField.ToString();
}
}
public class Program
{
public static void Main()
{
var foo = new Foo();
var referenceToPrivateField = foo.GetReference();
referenceToPrivateField = 100;
Console.WriteLine(foo);
}
}
Prior to that, you'd have to store the value in a field contained in an object, and pass around a reference to the object instead.
In this example I change the value from 0 to 100 from outside Foo, even though it is stored (indirectly) in a field that is private inside the Foo instance.
class ValueTypeReference<T> where T : struct
{
public T Value { get; set; }
}
class Foo
{
private ValueTypeReference<int> _privateField = new ValueTypeReference<int>{ Value = 0 };
public ValueTypeReference<int> GetReference()
{
return _privateField;
}
public override string ToString()
{
return _privateField.Value.ToString();
}
}
public class Program
{
public static void Main()
{
var foo = new Foo();
var referenceToPrivateField = foo.GetReference();
referenceToPrivateField.Value = 100;
Console.WriteLine(foo);
}
}
Output:
100
Well, if I udnerstood you correctly, you want the variable to have global scope, which can be achieved by putting variable as class field/property:
class Program
{
private static int _i;
static void Main()
{
_i = 0;
Add(100);
// now _i == 100
}
static void Add(int increment)
{
_i += 100;
}
}

Why isn't the value of class member changing?

Im fairly new to programming and am making a rpg battle simulator for practice. My problem is that I can't seem to make my attack method work. Heres the classes I have:
class Person
{
protected int attack;
protected int health;
public Person(int _attack, int _health)
{
attack = _attack;
health = _health;
}
public int GetAttack()
{
return attack;
}
public int GetHealth()
{
return health;
}
public int Attack(int _health)
{
_health -= attack;
return _health;
}
}
class Hero : Person
{
public Hero(int _attack, int _health)
:base (_attack , _health)
{
}
}
class Enemy : Person
{
public Enemy(int _attack, int _health)
:base (_attack , _health)
{
}
}
and heres the main:
class Program
{
static void Main(string[] args)
{
Hero Joe = new Hero(4, 10);
Enemy Tim = new Enemy(5, 20);
Joe.Attack(Tim.GetHealth());
Console.WriteLine(Tim.GetHealth());
Console.WriteLine(Tim.GetAttack());
Console.ReadLine();
}
}
My guess is that the attack method is doing the math, but is never changing the health that is passed into it. Or maybe it has something to do with the fact that their protected. Another thought of mine is that it doesn't need to return anything.
How would I go about making my attack method work? I just want it to take in somethings health value, subtract the attacking things attack value, and save the calculated value as the health? Thank you for reading this !
When you pass around an int, you are making copies of the number, not passing references to the same number in memory.
When you pass around an instance of a class, you are passing around references to the same object in memory.
Therefore, I suggest changing your design to something like this:
public void Attack(Person target)
{
target.health -= this.attack;
}
...
Joe.Attack(Jim);
You got a couple things you can improve here. First thing is naming conventions, I recommend reading the design guidelines.
First, If you change your Attack and Health to properties instead of protected fields, you expose getter and setter methods for it. Obviously you only want to set form the controller so make the set a private set:
public class Person
{
public int Attack { get; private set; }
public int Health { get; private set; }
public Person(int attack, int health)
{
Attack = attack;
Health = health;
}
// Rest of code
}
When you do it like this you eliminate the need for your individual GetAttack() and GetHealth() methods.
Next, the names of your parameter in Attack() is misleading. I assume you want the parameter to be "attack" and not "health" right? Since our setter is private this method allows us to only access health modifications inside the class. Since we already changed Health to be a property, we don't need to return it anymore so this method can now be void:
//Our property is named Attack so this has to be AttackAction or something different
public void AttackAction(int attack)
{
Health -= attack;
}
And if we put it all together:
public class Person
{
public int Attack { get; private set; }
public int Health { get; private set; }
public Person(int attack, int health)
{
Attack = attack;
Health = health;
}
public void AttackAction(int attack)
{
Health -= attack;
}
}
public class Hero : Person
{
public Hero(int attack, int health)
:base (attack , health)
{
}
}
public class Enemy : Person
{
public Enemy(int attack, int health)
:base (attack , health)
{
}
}
I made a fiddle here that shows this new code in action.
You are calling Attack() but are never saving the value returned by that method. You need to add a Setter for the health field, then set that value to the method's returned value. Something like
Health Property
public int Health
{
get { return health; }
set { health = value; }
}
Setting the Value
Tim.Health = Joe.Attack(Tim.Health);
If you want to keep the design pattern the same (you don't, see Blorgbeard's answer) you could add a SetHealth() method to Person and do something like this:
Tim.SetHealth(Joe.Attack(Tim.GetHealth());
This gets Tim's health total, passes that to Joe's attack method, which returns a value (what Tim's new health total should be) and then Tim's health is set to this value.

Show variable herited from interface on Unity inspector

I want to create some game in Unity and I've started by creating a class hierarchy in order to be able to use polymorphism. So I've created some interfaces with both methods and also variables.
As said in the C# interfaces documentation, I've created my interface with variables like this
public interface IUnit : ISelectable {
int healthPoint { get; set; }
bool isIndestructible { get; set; }
/******************************/
void takeDamage(int dmg);
void die();
}
Now, I'm implementing my interface in a class:
[System.Serializable]
public class BasicUnit : MonoBehaviour, IUnit {
private int _healthPoint;
public int HealthPoint { get { return (_healthPoint); } set { _healthPoint = value; } }
private bool _isIndestructible;
public bool isIndestructible { get { return (_isIndestructible); } set { _isIndestructible = value; } }
public void takeDamage (int dmg)
{
if (this.isIndestructible == false) {
this.HealthPoint -= dmg;
if (this.HealthPoint <= 0) {
die();
}
}
}
public void die()
{
Destroy(gameObject);
}
}
My problem is that my variables, healthPoint and isIndestructible are not shown in Unity's inspector despite being public variables. I've tried using [System.Serializable] but it doesn't work.
Well my question is quite simple, how should I do to show my inherited variables in Unity's inspector ?
Note: I'm trying to have nice and readable code, so if possible I would like to keep my IUnit class as an interface and my variables inside my IUnit.
It's not your inherited code that's hidden. Inheritance has no effect whatsoever in the display of the fields.
Rather, what's really happening is that you have two fields that are serializeable, but marked private (_healthPoint & _isIndestructible),
and two public Properties. Unfortunately, Unity can't process and display properties out of the box.
Fortunately, here's a simple solution. I found this on Unity Wiki, and saved it for a situation like this :)
Expose Proerties in Inspector from Unity Wiki
How it works
Basically, any Monobehavior that you want the properties exposed on should inherit from ExposableMonoBehaviour and also
1. private fields (like your _healthPoint) should have the [SerializeField, HideInInspector] attributes
2. public properties (like HealthPoint) should have the [ExposeProperty] attribute
Partial example
public class BasicUnit : ExposableMonoBehaviour, IUnit {
[SerializeField, HideInInspector]
private int _healthPoint;
[ExposeProperty]
public int HealthPoint {
get { return (_healthPoint); }
set { _healthPoint = value; }
}
}
If still anyone have problem with setting value of the variables inherited from an interface in inspector, Thanks to Jetbrains Rider , I found a solution. just use [field: SerializeField] before introducing the variable in the child script.
example :
public interface IAlive
{
float HealthPoint { get; set;}
}
public class Cat : MonoBehaviour , IAlive
{
[field: SerializeField] float HealthPoint { get; set;}
}
I found it, you can use [SerializeField] on any field you want to show in the inspector. However, it have to be used on the private variable you want to serialize, not the public one.
public class BasicUnit : MonoBehaviour, IUnit {
[SerializeField]
private int _healthPoint;
public int HealthPoint { get { return (_healthPoint); } set { _healthPoint = value; } }
[SerializeField]
private bool _isIndestructible;
public bool isIndestructible { get { return (_isIndestructible); } set { _isIndestructible = value; } }
}

Accessing parameters from 'object' type in C#

I am converting a VB.Net application to C# (as well as learning C#) and I ran into a problem. One of the functions takes in an object and applies modifications to certain parameters based on what is passed. This way, one function can be used to update any control passed to it, which is working fine in VB.
The full function has a lot more logic behind it, but here is a scaled back version showing the basics:
public void TransformObject(object objObject, int LeftPadding, int TopPadding, int WidthChange, int HeightChange)
{
objObject.Top = TopPadding;
objObject.Left = LeftPadding;
objObject.Width = WidthChange;
objObject.Height = HeightChange;
}
The problem is that 'Top', 'Left', 'Width', 'Height', etc. are not defined, since it is using the object type.
Is there a way to keep the existing structure without having to create a separate function or definition for each possible control type?
EDIT: I am using the .Net 3.5 framework.
You can use dynamic:
public void TransformObject(object objObject, int LeftPadding, int TopPadding, int WidthChange, int HeightChange)
{
dynamic dynObject = (dynamic)objObject;
dynObject.Top = TopPadding;
dynObject.Left = LeftPadding;
dynObject.Width = WidthChange;
dynObject.Height = HeightChange;
}
Or find an interface/base class (possibly Control?) that all these types have in common and use it in method signature, instead of object.
Use a base class, like MyBaseClass that has definitions for Top, Left, Width, and Height
public class MyBaseClass
{
public int Top {get; set;}
public int Left{get; set;}
public int Width {get; set;}
public int Height {get; set;}
}
and every class that you want to pass in, should derive from that base class
public class MyDerivedClass : MyBaseClass
{
}
You will need to determine if the objects passed to the function implement the same interface or inherit from the same base class that exposes those properties. If they do then simply change the interface of the function so you accept the common interface/base class type as the parameter rather than object. If not then you are left with nasty choices.
One of the solutions here is the use of interfaces. For example if I understand your question right you could try this:
public interface IMyInterface
{
int Top { get; set;}
int Left { get; set; }
int Width { get; set; }
int Height { get; set; }
}
public void TransformObject(object objObject, int LeftPadding, int TopPadding, int WidthChange, int HeightChange)
{
if (objObject is IMyInterface)
{
((IMyInterface)objObject).Top = TopPadding;
((IMyInterface)objObject).Left = LeftPadding;
((IMyInterface)objObject).Width = WidthChange;
((IMyInterface)objObject).Height = HeightChange;
}
}
Code is not optimized but this should do the trick :)
I would venture a guess that the object being passed is in fact a Control (assuming this is a WinForms application). You could change the method signature to specify this and see if that is in fact the case, or you could cast the object to a Control and test thoroughly (and/or add logging if the cast fails:
Changing the signature:
public void TransformObject(System.Windows.Forms.Control objObject, int LeftPadding, int TopPadding, int WidthChange, int HeightChange)
{
objObject.Top = TopPadding;
objObject.Left = LeftPadding;
objObject.Width = WidthChange;
objObject.Height = HeightChange;
}
Downcasting internally:
public void TransformObject(object objObject, int LeftPadding, int TopPadding, int WidthChange, int HeightChange)
{
var control = objObject as System.Windows.Forms.Control;
if (control != null)
{
control.Top = TopPadding;
control.Left = LeftPadding;
control.Width = WidthChange;
control.Height = HeightChange;
}
else
{
// Turns out it isn't a control, throw an exception or Log it
}
}
Don't you define the new instance of the object before calling the method.
object obj = new object()
TransformObject(obj,5,5,5,5)
public void TransformObject(object objObject, int LeftPadding, int TopPadding, int WidthChange, int HeightChange)
{
objObject.Top = TopPadding;
objObject.Left = LeftPadding;
objObject.Width = WidthChange;
objObject.Height = HeightChange;
}

What does inconsistent accessibility mean in C#?

im trying to use this method to make my characters but i get the error:
inconsistent accessibility:return type'consoleapplication1.Enemigo' is less accesible than
method 'consoleapplication1.poringbuilder.makeporing()'
its the first time i get this error and i really dont know what to do,i have tried alot of different ways but i get the same mistake plz help >.<
namespace ConsoleApplication1
{
public static class PoringBuilder
{
public static Enemigo MakePoring()
{
return new Enemigo(15, 0, 30,15, false, false,"Poring");
}
}
this is another class
namespace ConsoleApplication1
{
class Enemigo:Personaje
{
public Enemigo(int Damage, int Defensa, int HP,int MP, bool Evade, bool Counter, string Nombre)
: base(Damage, Defensa, HP,MP, Evade, Counter, Nombre)
{
}
}
}
this is the parent of all my classes
namespace ConsoleApplication1
{
class Personaje
{
public int Damage;
public int Defensa;
public int HP;
public int MP;
public bool Evade;
public bool Counter;
public string Nombre;
//public Personaje() { }
public Personaje(int Damage, int Defensa, int HP,int MP, bool Evade, bool Counter, string Nombre)
{
this.Damage = Damage;
this.Defensa = Defensa;
this.HP = HP;
this.MP = MP;
this.Evade = Evade;
this.Counter = Counter;
this.Nombre = Nombre;
}
}
}
and im using it on the main program like this
List<Enemigo> EnemigosNoob = new List<Enemigo>();
EnemigosNoob.Add(PoringBuilder.MakePoring());
i hope im precise enough >.< i tried making it public and its not solving anything >.<
Your MakePoring method is public, while your Enemigo class is not.
You need to declare the Enemigo class as public:
public class Enemigo
Your class Enemigo is private in the namespace. You need to declare it as public.

Categories

Resources