How to access method by using properties in c#? - c#

I will give you an example for understanding of my question.
transform.translate() (transform is a property and translate is a method)
But how transform can access to translate.
Example :
class ExampleClass
{
public int exampleprop
{ get; }
public void examplemethod()
{
}
}
I want to make just like that : exampleprop.examplemethod()
And is there any way to make this.
(thats why i ask this questions is there are kind of code line in unity called transfom.translate. And i can't understand it.)

In your example, exampleprop.examplemethod() is not valid because exampleprop is an int and ints do not have a method called exampleprop.
The way you would access examplemethod() is to first create a new object of type ExampleClass then access examplemethod() as normal. Here's an example:
class ExampleClass {
public void ExampleMethod() {
// code for example method goes here.
}
}
Then somewhere you need to "new up" an ExampleClass and call the ExampleMethod method.
ExampleClass foobar = new ExampleClass();
foobar.ExampleMethod();

Related

How to get the name of the class which contains the method which called the current method?

I have a requirement where I need to know the name of the class (ApiController) which has a method (GetMethod) which is called by another method (OtherMethod) from a different class (OtherClass).
To help explain this, I hope the below pseudo-code snippets help.
ApiController.cs
public class ApiController
{
public void GetMethod()
{
OtherMethod();
}
}
OtherClass.cs
public class OtherClass()
{
public void OtherMethod()
{
Console.WriteLine(/*I want to get the value 'ApiController' to print out*/)
}
}
What I've tried:
I've looked at How can I find the method that called the current method? and the answers will get me the calling method (OtherMethod) but not the class (ApiController) which has that method
I tried [CallerMemberName] and using StackTrace properties but these don't get me the method's class name
using System.Diagnostics;
var className = new StackFrame(1).GetMethod().DeclaringType.Name;
Goes to the previous level of the Stack, finds the method, and gets the type from the method. This avoids you needing to create a full StackTrace, which is expensive.
You could use FullName if you want the fully qualified class name.
Edit: fringe cases (to highlight the issues raised in comments below)
If compilation optimizations are enabled, the calling method may be inlined, so you may not get the value you expect. (Credit: Johnbot)
async methods get compiled into a state machine, so again, you may not get what you expect. (Credit: Phil K)
So it can be done like this,
new System.Diagnostics.StackTrace().GetFrame(1).GetMethod().DeclaringType.Name
StackFrame represents a method on the call stack, the index 1 gives you the frame that contains the immediate caller of the currently executed method, which is ApiController.GetMethod() in this example.
Now you have the frame, then you retrieve the MethodInfo of that frame by calling StackFrame.GetMethod(), and then you use the DeclaringType property of the MethodInfo to get the type in which the method is defined, which is ApiController.
You can achieve this by below code
First you need to add namespace using System.Diagnostics;
public class OtherClass
{
public void OtherMethod()
{
StackTrace stackTrace = new StackTrace();
string callerClassName = stackTrace.GetFrame(1).GetMethod().DeclaringType.Name;
string callerClassNameWithNamespace = stackTrace.GetFrame(1).GetMethod().DeclaringType.FullName;
Console.WriteLine("This is the only name of your class:" + callerClassName);
Console.WriteLine("This is the only name of your class with its namespace:" + callerClassNameWithNamespace);
}
}
The instance of stackTrace is depend upon your implementation environment. you may defined it locally or globally
OR
You may use below method without creating StackTrace instance
public class OtherClass
{
public void OtherMethod()
{
string callerClassName = new StackFrame(1).GetMethod().DeclaringType.Name;
string callerClassNameWithNamespace = new StackFrame(1).GetMethod().DeclaringType.FullName;
Console.WriteLine("This is the only name of your class:" + callerClassName);
Console.WriteLine("This is the only name of your class with its namespace:" + callerClassNameWithNamespace);
}
}
Try this may it help you
Why not simply pass the name as constructor parameter? This doesn't hide the dependency, unlike StackFrame/StackTrace.
For example:
public class ApiController
{
private readonly OtherClass _otherClass = new OtherClass(nameof(ApiController));
public void GetMethod()
{
_otherClass.OtherMethod();
}
}
public class OtherClass
{
private readonly string _controllerName;
public OtherClass(string controllerName)
{
_controllerName = controllerName;
}
public void OtherMethod()
{
Console.WriteLine(_controllerName);
}
}

feeding a Type into a constructor

class Program{
void Apple(){
List<Banana> apple = new List<Banana> { (new Banana(Cucumber, 5)), (new Banana(Dates, 6)) };
}
}
class Banana{
public Banana(Type eggplant, int feijoa){
new eggplant(feijoa);
}
}
class Cucumber{
public Cucumber(int feijoa){
}
}
class Dates{
public Dates(int feijoa){
}
}
basically it feeds a bunch of information from the program class to the Banana class, which then filters that information and uses it to create instances of a bunch of different classes.
the problem is within the Program class, where even though it registers that a Type is needed to complete the Banana constructor, when given a Type, like Cucumber or Dates, it says giving a type there is not considered valid in the given context, so i would like some help with understanding how to fix it, thanks in advance.
while structuring my program this way might seem weird and inefficient, it's mostly to help simplify viewing and editing the front end of my program.
you should use typeof operator while passing argument to constructor.
Like :
List<Banana> apple = new List<Banana> { (new Banana(typeof(Cucumber), 5)), (new Banana(typeof(Dates), 6)) };
However inside constructor you need to use Activator.CreateInstance(typeof(T), object[] args) to instantiate either Cucumber or Banana objects.
Also you better consider redesigning your class like :
class Banana<T> where T: new(){
public Banana(int feijoa){
Activator.CreateInstance(typeof(T), new object[]{feijoa}
}
so your snippet would be changed to :
List<Banana> apple = new List<Banana> { (new Banana<Cucumber>(5)), (new Banana<Dates>(6)) };
To get the Type instance of Cucumber class you should use typeof(Cucumber). So your constructors should change to look like the following:
new Banana(typeof(Cucumber), 5)
new Banana(typeof(Dates), 6)
UPDATE
Here is some more context regarding your code. The constructor of the Banana type is actually incorrect.
It's not possible to call new on a type instance. What you're actually trying to do is instantiate an object of the passed eggplant parameter. There are multiple ways you can achieve that. But before going into details I recommend you to read about type constructors first.
Besides, it's a bit unclear what your intent is. What you're trying to do with the newly created instance. I would just assume for now that you're going to store that instance in some member variable, as follows:
public class Banana
{
private readonly object instance;
public Banana(Type eggplant, int feijoa)
{
this.instance = Activator.CreateInstancenew eggplant(feijoa, new object [] {feijoa});
}
}
Here I've used the Activator type which will create an instance of a given type if it'll find a matching constructor based on the parameters you've passed. Otherwise, an exception will be thrown.
While the above-mentioned approach would work, it's not ideal as it provides no type safety. So it would be great to use Generics here, but that is not possible with current code because of the requirement of having a constructor, which accepts a parameter. There is still a way to achieve that, but it'll require a lot of code changes, which is not directly related to your question. You can read more about Generics here.
While there are a lot of other options, I would ask whether it's really a requirement to have the design you've got here. Why not pass in the instances to the Banan class directly. To do that, you'll need to make sure there is a base class/interface, which all the potential parameters to the Banana constructor will extend. Here is an example you could go with:
class Program
{
void Apple()
{
List<Banana> apple = new List<Banana> { new Banana(new Cucumber(5)), new Banana(new Dates() { Feijoa = 6 }) };
}
}
class Banana
{
private readonly ICommon instance;
public Banana(ICommon instance)
{
this.instance = instance;
}
}
public interface ICommon
{
int Feijoa { get; set; }
}
class Cucumber : ICommon
{
public Cucumber(int feijoa)
{
this.Feijoa = feijoa;
}
public int Feijoa { get; set; }
}
class Dates : ICommon
{
public Dates()
{
}
public int Feijoa { get; set; }
}
Sorry, the provided context is not enought to be more specific. In the meantime, I tried to share as much as possible. I know, it may look scattered a bit.
Hope this helps.

C# Access to subclass Proprieties from base class instance

I don't really know how to formulate my issue it's a bit complicated for me, i'll try my best to explain.
I'm making a space game, i have a base class which represent places, and i want to have different type of places like planets, space stations, asteroïds, trading ships etc. The player can click on those objects and get informations.
So my classes looks like something like this:
public class Place {
public int placeId;
public string placeName;
public string placeDescription;
/* Place constructor */
}
public class Planet : Place {
/* Specific proprieties of planet */
public PlanetType planetType;
public int planetSize;
...
// Planet constructor
public Planet(int placeId, string placeName, string placeDescription, PlanetType planetType, int planetSize) : base(placeId, placeName, placeDescription) {
this.planetType = planetType;
this.planetSize = planetSize;
...
}
}
And i have a delegate which accept a function like selectPlace with Place in parameters because i don't want to make a delegate for each type of Place i have.
In another script which is supposed to show the information of any kind of Place, i recieves the Place object that the player clicked on. I think i found a solution, however is this correct to do something like this ?
private void updateSelectedPlaceUI(object sender, EventsController.PlaceEventArgs placeArgs){
// This is just a test, i should check which type of subclass it is before
Planet planetTest = placeArgs.Place as Planet; // So now i can use planetTest.planetType
}
And placing this in a switch case so i can handle any type. I just want to be able to get the proprieties from any derived class of Place in order to display them in UI. I would like to know a better way to achieve this.
But i'm wondering if my design is ok and necessary, it has been a while since i haven't used inheritance / polymorphism, and i feel like i'm doing it the wrong way.
I would propably make the UI part of showing the properties a specific place generic to accept something like a PropertyItem, you can decide the properties yourself.
public class PropertyItem
{
public string Text { get; set; }
public object Value { get; set; }
}
And then in your select method you would just call the abstract method of your base class (make your base class abstract as well)
public abstract class Place
{
...
public abstract IEnumerable<PropertyItem> GetProperties();
}
And now you can override this in your Planet
public class Planet : Place
{
...
public override IEnumerable<PropertyItem> GetProperties()
{
yield return new PropertyItem { Text = "Size", Value = this.planetSize };
}
}
And eventually you would use the GetProperties() method to get the properties of your place and show them in a tabular or what ever format your UI knows how to handle the PropertyItem type.
private void updateSelectedPlaceUI(object sender, EventsController.PlaceEventArgs placeArgs)
{
MyUserInterfaceWidget.DisplayProperties(placeArgs.Place.GetProperties());
}

Why am I able to use variables inside a null reference?

I'm not really sure how to describe it exactly so let me show you what is going on.
I have a PlayerControls script which looks like this (note: I stripped everything except for the necessities).
namespace Player.Controls {
internal class PlayerControls: MonoBehaviour {
public bool IsClimbing { get; private set; } = false;
public bool IsGrounded { get; private set; } = false;
}
}
These variables are set in this class depending if the player is climbing/touching the ground. This script resides on the "Player" GameObject in the scene.
I have another script called PlayerControllerwhich looks like this
using Player.Controls;
public class PlayerController: Singleton<PlayerController> {
internal PlayerStats stats = new PlayerStats();
//PlayerStats nested class (see below)
}
The Singleton class only checks if the generic type is null, if it is, it will use FindObjectOfType to get an instance. This script also resides on the "Player" GameObject.
Inside the PlayerController class, I have a nested class called PlayerStats. It looks like this
internal class PlayerStats : PlayerControls {
public new bool IsClimbing { get { return base.IsClimbing; } }
public new bool IsGrounded { get { return base.IsGrounded; } }
}
Notice this nested class in inheriting from PlayerControls.
The idea is that the PlayerControls class in inaccessible to all other classes except for PlayerController, and any information I want to obtain regarding the player can be obtained by getting the player's instance (via the singleton) and accessing the PlayerStats variable.
For example, assuming the variable inside Singleton which holds the instance is called Instance, one could do PlayerController.Instance.stats.IsClimbing; Everything works as expected, except for one thing.
In the Awake method of the PlayerController class, I do this
private void Awake() {
Debug.LogFormat("In PlayerController Awake(). Is PlayerController.stats null? {0}",
(stats.Equals(null) ? "Yes" : "No"));
Debug.LogFormat("IsClimbing : {0}", stats.IsClimbing);
}
In the output window, it prints
In PlayerController Awake(). Is PlayerController.stats null? Yes
IsClimbing : False
If I also put the same IsClimbing debug in the Update() method, the value is correct for when I start climbing.
So, finally, my question, how can I access the variables of the PlayerStats class with the stats variable if stats is null? I thought it may have been somehow calling straight to the PlayerControls properties, so I changed their names, removed the new inside of PlayerStats and even put a debug statement inside one of the properties inside PlayerStats, and it definitely gets called. For example,public bool IsClimbing { get { Debug.Log("Called IsClimbing inside PlayerStats."); return base.Climbing; } }
If it is getting called and working properly, how can it be null? I asked my professor and he doesn't seem to know why either. What is really going on here?
Edit:
As requested, the Singleton class:
public abstract class Singleton<T>: MonoBehaviour where T : MonoBehaviour {
private static T instance;
public static T Instance {
get {
if(instance == null) {
instance = FindObjectOfType<T>();
}
return instance;
}
}
}
Here is an image of the console output.
Digging around on the Unity forums it appears that the Equals method has been overridden (on Object which MonoBehaviour eventually derives from) which is why comparing a MonoBehaviour to null is not giving you what you might expect. The answer I link to suggests code like this is more appropriate:
stats == null || stats.Equals(null)

Triggering a non-static class from a static class?

I am writing a class library(API) in C#. The class is non-static and contains several public events. Is it possible to trigger those events from a static method in a separate class?
For example...
class nonStaticDLLCLASS
{
public event Event1;
public CallStaticMethod()
{
StaticTestClass.GoStaticMethod();
}
}
class StaticTestClass
{
public static GoStaticMethod()
{
// Here I want to fire Event1 in the nonStaticDLLCLASS
// I know the following line is not correct but can I do something like that?
(nonStaticDLLCLASS)StaticTestClass.ObjectThatCalledMe.Event1();
}
}
I know you typically have to create an instance of the non-static class in order to access it's methods but in this case an instance has already been created, just not by the class that is trying to access it.
No, instance members can only be invoked/accessed on a valid instance of the type.
In order for this to work you must pass an instance of nonStaticDLLCLASS to StaticTestClass.GoStaticMethod and use that instance reference to invoke/access the non-static members.
In your example above how do you specify which instance of the type you are accessing? The static method has no knowdlege of any instance so how does it know which one to use or if there are any loaded in memory at all?
Consider this example:
using System;
class Dog
{
public String Name { get; set; }
}
class Example
{
static void Main()
{
Dog rex = new Dog { Name="Rex" };
Dog fluffy = new Dog { Name="Fluffy" };
}
static void sayHiToDog()
{
// In this static method how can I specify which dog instance
// I mean to access without a valid instance? It is impossible since
// the static method knows nothing about the instances that have been
// created in the static method above.
}
static void sayHiToDog(Dog dog)
{
// Now this method would work since I now have an instance of the
// Dog type that I can say hi to.
Console.WriteLine("Hello, " + dog.Name);
}
}
Instance methods can only be called on instances. In your example, the instance is calling the static method. Can you give the static method a parameter allowing the instance to pass in a reference to itself? Something like this:
class nonStaticDLLCLASS
{
public event Event1;
public CallStaticMethod()
{
StaticTestClass.GoStaticMethod(this);
}
}
class StaticTestClass
{
public static GoStaticMethod(nonStaticDLLCLASS instance)
{
// Here I want to fire Event1 in the nonStaticDLLCLASS
// I know the following line is not correct but can I do something like that?
instance.Event1();
}
}
I think you need to clarify your question to specify why you can't do something like this, or why the instance can't raise its own event.

Categories