Maybe a silly question, but having difficulty understanding it.
public class A
{
public void Message()
{
Debug.Log("Some Message")
}
}
public class B: MonoBehaviour
{
A obj1 = new A(); //instance of object is made and constructor is called
A obj2; // object is made
obj1.Message();
obj2.Message();
void Start(){}
void Update(){}
}
What's the purpose of 'new' keyword if in both cases, the object is able to use methods of the class
A obj2; // object is made
The object is not instantiated at this time, you only told here that you have a variable with the name obj2, and it is hold reference to nothing, in case of class it is null. You have a class named A and in it, you have a method called Message() and compiler in compile-time have a signal you have Message method defined, and that it is. In this case, this code should throw an exception NullReferenceException
There are a few quirks to Unity which may be tripping you up here. Actually, obj2 is not null, because it is of type "A" (not a Monobehavior). Since Class B is derived from Monobehavior, all of its "class variables" (the ones defined in immediate scope) will be instanced by the Inspector automatically. You can read about that here.
In other words, obj2 will still be usable. This is a property of custom classes in regards to how they are loaded from MonoBehaviors. If class A was also a MonoBehavior, then it would be nullable here, and you would see it as an empty variable in your inspector when Class B is put onto a GameObject. This is the case where Message() would not work, since obj2 would actually be null. Note there are other complications though--if Class A is a MonoBehavior, then you shouldn't be using Constructors on it, you should be using AddComponent(). Also, you can't define two MonoBehaviors in the same script file.
Finally, I'm not sure of the specifics here since I haven't tested it, but obj1.Message() may not be able to be called from where you're currently doing it. Typically code is run using the Callback functions provided by the MonoBehavior inheritance, i.e. Start(), Update(), etc. In order to call obj1.Message() at the start of the game, you need to run it from the Start() method. Let me know if you have any questions and I can clear up anything you find confusing!
EDIT: This is only true if obj2 appears in the inspector--if it is public and the class A is tagged as Serializable.
Related
Destroy() method is not accessible in static method
public static void Die()
{
Destroy(gameObject);
}
But Destroy() is only accessible if:
public void Die()
{
Destroy(gameObject);
}
You can't call a non static function from a static function but you can do the opposite.
I need to make it accessible on another scripts
Make the Die function to be a non static function. Let's say that this script is named OtherScript.
public void Die()
{
Destroy(gameObject);
}
Then from another script, you can access it by finding the GameObject the OtherScript script is attached to with the GameObject.Find function then use the GetComponent function to get the OtherScript reference from the GameObject:
OtherScript otherScript;
void Awake()
{
GameObject obj = GameObject.Find("NameOfGameObjectOtherScriptIsAttachedTo");
otherScript = obj.GetComponent<OtherScript>();
}
You can now call the Die function with otherScript.Die(). Note that you must replace "NameOfGameObjectOtherScriptIsAttachedTo" with the name of GameObject the OtherScript script is attached to.
From your comments it looks more like you actually want to do what Programmer's answer shows.
I'm just adding this because your title asks How to Destroy Object from static method in Unity C#
If you really need it to be static (e.g. in a static class) you could use it like this
using UnityEngine;
public static class SomeStaticClass
{
public static void Die(GameObject obj)
{
Object.Destroy(obj);
}
}
but to be honest this is needed in very few cases. It might be helpful e.g. in an Editor script where you don't have any Component executing your code.
cannot kill a single static object, it dosnt work that way. please refer to the answer here.
the following excerpt is from the above link, and should explain for you...
*I think perhaps you've misunderstood the 'static' keyword a little bit.
To clarify, a bit... Imagine you have a class called 'Vehicle'.
A none-static variable means 'every vehicle has its own copy of this variable'. We might say 'every instance of vehicle has its own copy of the variable.
A static variable means 'there is only 1 of this value shared by all vehicles'. Here we'd say 'all instances of vehicle share the variable.
Following on from that, functions are a little harder to picture, but they work in much the same way:
A none-static function operates on an instance of the vehicle. The result is that it can use the 'this' operator (it makes sense!) and access both none-static member variables of it's instance, and the shared static ones
A static function isn't tied to an individual instance of a vehicle, so the 'this' operator doesn't make any sense (what would 'this' be?). It still makes sense for it to be able to access static variables, but again none-static ones don't make any sense - who's version of the variable would it be referring to?
Your 'Die' function looks like it is designed to operate on a given instance of your enemy. i.e. you are expecting calling 'Die' to mean 'kill this please'. As a result it should not be static. You'll also need to access the 'gameObject' variable, not the 'GameObject' type.*
This code has been UPDATED.
Robot.cs:
struct state systemcheck()
{
state stateInfo = new state();
public double x,y,z;
}
Main.cs:
public state stateInfo;
private readonly Sub cpnew;
public Main()
{
InitializeComponent();
cpnew = new Sub(this);
}
Sub.cs:
public state systinfo;
private readonly Main main;
public Sub(Main main)
{
InitializeComponent();
this.main = main;
systinfo = this.main.stateInfo;
}
Here,systinfo.X provides a null value. But mainfrm.stateInfo.X provides the correct value but throws marshal-by-reference class warning.
What is the correct way of initializing systinfo? The values of state are obtained from a robot connected from the external.
It's a good thing you asked - remember to always follow the warnings unless you absolutely know what you're doing. In this case, you most definitely do not know what you're doing.
Form is a class - and all classes are reference types in .NET. This has several implications, one of which is highly relevant here - they are always passed by reference. In other words, when you use Main main as an argument, you are already passing a reference (similar to passing a pointer to Main in C).
Using ref, you're passing a reference to the reference. This allows you to modify the outside reference from inside of the method. That's not what you want here - as a simple example, it would allow you to write an increment method:
public void Increment(ref int value)
{
value = value + 1;
}
If you didn't use ref, this would simply modify the local value of value. With ref, it modifies the local in the caller.
In your case, the proper code would be closer to
public state stateInfo;
private readonly Sub cpnew;
public Main()
{
InitializeComponent();
cpnew = new Sub(this);
}
Form2:
public state systinfo;
private readonly Main main;
public Sub(Main main)
{
InitializeComponent();
this.main = main;
systinfo = mainfrm.stateInfo;
}
So, what is the warning telling you? Form inherits from MarshalByRefObject. This implies that you might not actually be passing the real Form object - it's entirely possible you only have a proxy to a Form on a remote computer, for example. This means that all the calls on the type are automatically marshalled through the proxy, executed on the actual instance, and the result returned. Since state is a struct (and I'm betting it's because you don't understand the difference between C#'s struct and C's struct), it's a value-type - and if you are indeed holding a proxy instead of the real instance, this will cause a runtime exception.
To get around the warning, you could copy out the state to a local first - that makes it safe (and more importantly, obvious).
There's a lot of traps you can drop into when switching from C++ to C# - they look similar on the surface, but there's many differences. Try looking up a bit about whatever you're trying to use before you actually do - for example, looking up the ref keyword would make it obvious that you're making a pointer to a pointer, and looking up struct and class will tell you that they behave completely differently from C++. Just be careful.
Coding in C# idiomatically gets even more serious. For example, you usually create sub-forms and dialogs where you need them, rather than creating an instance in the constructor and reusing it when needed. And of course, circular references are usually a terrible idea - it's a great way to increase the code complexity, and it makes debugging and testing more expensive. Further refactoring hurts a lot more with circular references as well.
Say I have this class:
[AttributeUsage(AttributeTargets.Method)]
public class MyAttribute : Attribute
{
public MyAttribute()
{
// Do stuff
}
~MyAttribute()
{
// When is this called? When the function ends? Whenever the GC feels like?
}
}
Following an example call of GetCustomAttributes through in Reflector, the managed part of the code (i.e. the point at which it transitions to the runtime and becomes an external call) is down in CustomAttribute.GetCustomAttributes.
At this point, the method is examining the bytes of the metadata surrounding the object for which the attributes are being loaded.
There is code in there which then does further reflection to find the runtime constructor being called. E.g.
[MyAttribute]
Would be calling the default, whereas
[MyAttribute(1, "hello", typeof(T))]
Would be calling a constructor that takes (Int, String, Type).
I can't see any evidence in there that any caching of instances is performed which therefore means that attribute instances are created on demand when they are reflected.
Proof
The aforementioned managed-runtime transition happends at CustomAttribute._CreateCaObject. Whilst not easy to statically analyse whether this method does in fact cache the instances it creates (it does potentially get enough state information in the form of a memory buffer pointer presumably indicating the location in metadata where the attribute declaration resides) we can look at the facts:
The constructor is always called, and
New constructor parameters are always read and fed in.
This tells me that the attribute is always constructed.
We can test for this, of course, by writing a piece of code in a test.
[TestMethod]
public void TestMethod1()
{
//if running in MSTest you have to allow for the test runner to reflect
//over the class as it looks for the TestClass attribute - therefore if our
//assumption is correct that a new instance is always constructed when
//reflecting, our counter check should start at 2, not 1.
Type t = typeof(AttributeTest);
var attributes =
t.GetCustomAttributes(typeof(AttributeTest.TheAttributeAttribute), false);
//check counter
Assert.AreEqual(2, AttributeTest.TheAttributeAttribute.Counter);
var attributes2 =
t.GetCustomAttributes(typeof(AttributeTest.TheAttributeAttribute), false);
//should be one louder (sorry, 'one bigger' - the Spinal Tap influence :) )
Assert.AreEqual(3, AttributeTest.TheAttributeAttribute.Counter);
}
[TheAttribute]
public class AttributeTest
{
public class TheAttributeAttribute : Attribute
{
static int _counter = 0;
public static int Counter { get { return _counter; } }
public TheAttributeAttribute()
{
_counter++;
Console.WriteLine("New");
}
}
}
Therefore an efficient use of metadata attributes would be to cache them in user code, unless of course the attribute is mutable in some way that makes it not applicable for all instances of a given T, or all 'instances' (in quotes because of course a method is only stored in memory once) of a method m for instances of type T).
Following this, therefore, an attribute is available to the GC once all references to it in code have been nulled. The same is true for all members of that attribute as well.
Therefore a method which uses GetCustomAttributes() to retrieve an attribute, uses it and then throws away the reference has just released a new instance of that attribute for the GC to clean up when it needs to.
Therefore - attribute instances are governed by the exact same memory management and lifetime rules as all class instances; therefore what #PieterG says in his answer is correct - the destructor could be called at any time after all references to that attribute have been released.
Whenever the GC Feels like it
Destructors cannot be called. They are invoked automatically.
Destructors (C# Programming Guide)
I am working on porting a VB6 application to C# (Winforms 3.5) and while doing so I'm trying to break up the functionality into various classes (ie database class, data validation class, string manipulation class).
Right now when I attempt to run the program in Debug mode the program pauses and then crashes with a StackOverFlowException. VS 2008 suggests a infinite recursion cause.
I have been trying to trace what might be causing this recursion and right now my only hypothesis is that class initializations (which I do in the header(?) of each class).
My thought is this:
mainForm initializes classA
classA initializes classB
classB initializes classA
....
Does this make sense or should I be looking elsewhere?
UPDATE1 (a code sample):
mainForm
namespace john
{
public partial class frmLogin : Form
{
stringCustom sc = new sc();
stringCustom
namespace john
{
class stringCustom
{
retrieveValues rv = new retrieveValues();
retrieveValues
namespace john
{
class retrieveValues
{
stringCustom sc = new stringCustom();
9 times out of 10, infinite recursion bugs are caused by bad property accessors:
public class BrokenClass
{
private string name;
public string Name
{
get { return name; }
set { Name = value; } // <--- Whoops
}
}
I've also had it happen when doing major refactorings with method overloads; sometimes you accidentally end up with a method calling itself when it's supposed to call a different overloaded method.
Either way, you should be able to tell by looking at the call stack for the exception and checking for a repeating pattern. If you see one, then your problem is somewhere in that loop.
Edit - well, based on your example code, you definitely have infinite recursion in the initializers. I have no idea what that code is supposed to be doing, but it's never going to terminate. StringCustom immediately creates RetrieveValues which immediately creates another StringCustom, and so on.
This is one reason why circular class dependencies are typically considered a code smell. Whenever you see ClassA depending on ClassB and ClassB depending on ClassA then you should try to refactor; the exception is if ClassB is entirely owned and managed by ClassA (i.e. an inner class), which is clearly not the case here. You need to eliminate one of the dependencies somehow.
Just put a break point in the constructor of each class you initialize. If you keep accessing the same breakpoints over and over again, I would say infinite recursion is the cause.
I would also check the stack to see what is going on.
Yes, you have an infinite recursion going on because you have two classes which create an instance of the other class in their constructors. As soon as you create an instance of one class, it creates an instance of the other class, which creates an instance of the other class, which creates an instance of the other class etc. etc. etc.
You definitely need to refactor this.
Yeah, I think you are likely on the right track. You can sometimes see this easily in the debugger by looking at the call stack on a break point put at the line of code that causes the exception.
Sound like that is the issue. Can you not pass ClassA into the constructor for ClassB?
Well, everybody understands it. Why not suggest some solution then?
Now, I remember this situation. One way is to avoid calling another contructor inside one. So, there would be extra coding. Eg -
class A {
B b;
A() {}
void Init() { b = new B(); }
}
class B {
A a;
B() {}
void Init() { a = new A(); }
}
...
A aObj = new A();
aObj.Init();
...
B bObj = new B();
bObj.Init();
This will remove the recursion. This is, obviously, easiest way. :)
I had trouble coming up with a good way to word this question, so let me try to explain by example:
Suppose I have some interface. For simplicity's sake, I'll say the interface is IRunnable, and it provides a single method, Run. (This is not real; it's only an example.)
Now, suppose I have some pre-existing class, let's call it Cheetah, that I can't change. It existed before IRunnable; I can't make it implement my interface. But I want to use it as if it implements IRunnable--presumably because it has a Run method, or something like it. In other words, I want to be able to have code that expects an IRunnable and will work with a Cheetah.
OK, so I could always write a CheetahWrapper sort of deal. But humor me and let me write something a little more flexible--how about a RunnableAdapter?
I envision the class definition as something like this:
public class RunnableAdapter : IRunnable {
public delegate void RunMethod();
private RunMethod Runner { get; set; }
public RunnableAdapter(RunMethod runner) {
this.Runner = runner;
}
public void Run() {
Runner.Invoke();
}
}
Straightforward enough, right? So with this, I should be able to make a call like this:
Cheetah c = new Cheetah();
RunnableAdapter ra = new RunnableAdapter(c.Run);
And now, voila: I have an object that implements IRunner and is, in its heart of hearts, a Cheetah.
My question is: if this Cheetah of mine falls out of scope at some point, and gets to the point where it would normally be garbage collected... will it? Or does this RunnableAdapter object's Runner property constitute a reference to the original Cheetah, so that it won't be collected? I certainly want that reference to stay valid, so basically I'm wondering if the above class definition is enough or if it would be necessary to maintain a reference to the underlying object (like via some private UnderlyingObject property), just to prevent garbage collection.
Yes, that reference remains valid, and can in fact be retrieved using the Delegate.Target property -- in your code, as ra.Runner.Target.
As others said it counts as a reference. You might find this story interesting.
http://asserttrue.blogspot.com/2008/11/garbage-collection-causes-car-crash.html
If not, that sounds like a broken garbage collector.
Yes, the delegate counts as a reference. Your object will not be garbage collected until the delegate is also unreachable.