[EDIT]
For someone who came across this page for some reason,
things have changed now. Starting Unity 2017, you have to define the same symbol in both files(Callee and Caller) regardless of the file location.
Below was the issue before Unity 2017.
I'll leave this for the record.
In standard C#, if I want to call a method with a conditional attribute, I have to define a symbol for it in the file where the method is CALLED. But in Unity, it seems different. It only works when I put the line in the file where the method EXISTS. Let's say, there are two script files in a Unity project like this.
ClassForMySymbol.cs
class ClassForMySymbol {
[System.Diagnostics.Conditional("MY_SYMBOL")]
public static void Print() {
Debug.Log ("This method is called.");
}
}
Test.cs
public class Test : MonoBehaviour {
void Start() {
ClassForMySymbol.Print();
}
}
This will only work when I define "MY_SYMBOL" in ClassForMySymbol.cs but not Test.cs.
I don't get what's happening. Is this normal? What am I missing here?
PS. This question is not about #define's scope or defining a global symbol.
Related
I am using Unity 2019.3.13f1 and Visual Studio Community 2019 version 16.5.4. I have the script InterfaceContainer.cs as follows:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InterfaceContainer : MonoBehaviour {
// Start is called before the first frame update
void Start() {
}
// Update is called once per frame
void Update() {
}
}
public interface IItem {
public string Name { get; }
public string Path { get; }
public GameObject Icon { get; }
public void Open();
}
Visual Studio gives no compilation errors.
In Unity the inspector of the script says "No MonoBehaviour scripts in the file, or their names do not match the file name." And when I drag the script into a GameObject, it says "Can't add script component "InterfaceContainer" because this script class cannot be found. Make sure that there are no compile errors and that the file name and the class name match."
The names definitely match, because when I deleted the interface part the error didn't exist anymore.
I also tried deleting the class part. It didn't help.
Any subsequent scripts added had the exact same error, whether or not they contain any interfaces, or reference this script.
The weird thing is when I deleted the interface part of this script, refreshed Unity, added this part again, and refreshed Unity again, the error disappears. However all subsequently added scripts still have the same error.
I have no idea what causes this error, and have googled for a long time with no avail. Any help will be greatly appreciated.
EDIT: The error isn't gone when I removed the interface part and added it again; I can still drag the script as a component, when when I try entering playmode it asks me to fix all compiler errors.
Try this:
Right click in the Project Panel of Unity
Import New Asset... and select InterfaceContainer.cs
Try add this script as component again.
One thing I would try is to check if it happens in earlier versions of unity. With the unity hub its easy to have different versions of unity to check this kind of things. Its useful if you are working with one of the latests.
I can confirm that in 2018.4.12, I attach my monobehaviours with interfaces with no problem.
On the other hand you dont implement the Interface you define in your monobehaviour, although that should not be causing any problem, have you tried if implementing the interface in your monobehaviour if you got the error?
Hope that helps
I'm making a plugin based C# application in Unity 5.6, where some plugins might sometimes be installed, sometimes not.
In my plugin Plugin1, I have a component Plugin1.Component1. In that same project, I implement a custom editor for it, called Plugin1.Component1Editor, that is a [CustomEditor(typeof(Plugin1.Component1))]. When Plugin1 is installed, the Component1 is available, and rendered with the custom editor.
My plugin Plugin2 depends on Plugin1. Depending on settings in its component Plugin2.Component2, it would like to alter the custom editor for Plugin1.Component1.
I have implemented a new custom editor in Plugin2, called Plugin2.Component1Editor, that is also a [CustomEditor(typeof(Plugin1.Component1))]. It inherits from UnityEditor.Editor, not from Plugin1.Component1Editor, as the latter caused problems with serialized properties not being found in Plugin1.Component1Editor.
Plugin2.Component1Editor won't collide with Plugin1.Component1Editor at compile time, as it has its own namespace. But what actually happens in the Unity inspector?
The behaviour when I test it is the desired behaviour: The Plugin2.Component1Editor renders the inspector, unless Plugin2 not installed. But why?
I don't want to trust that it will keep doing so unless I know why.
Thank you!
EDIT: I was wrong, it wasn't rendering the Plugin2.Component1Editor, it was the default Unity editor running. Neither of my custom editors are used. How can I specify which one I want to use?
It seems that the solution was indeed inheritance.
I made the serialized properties handled by Plugin1.Component1Editor and their retrieval protected instead of private, and then Plugin2.Component1Editor inherits from Plugin1.Component1Editor instead of UnityEditor.Editor. Then the Plugin2.Component1Editor became the rendering one, calling the Plugin1.Component1Editor as needed.
The main part of the solution was that I made the OnEnable call in Plugin1.Component1Editor, which retrieves the serialized properties, protected, so that I could call it from Plugin2.Component1Editor via base.OnEnable().
For anyone stumbling on this question, the OP's solution only works (for me at least) if you have Plugin1 and Plugin2, where as if you have Plugin3 the last plugin will not be loaded as a custom editor. So i came up with another solution to this.
I've decided to use an "Editor Hub", a custom editor for Component1, that looks for ICustomEditor interface implementations using System.Reflection, also Unity has a nice class like TypeCache which can get you loaded classes
public interface ICustomEditor
{
EditorType Type { get; }
void OnEnable(SerializedObject target);
void OnInspectorGUI(SerializedObject target);
}
I've decided to go for EditorType.Before or EditorType.After to render custom features before or after the main editor.
protected virtual void OnEnable()
{
CollectEditors();
OnEnableEditors();
}
public override void OnInspectorGUI()
{
OnInspectorGUIBefore();
base.OnInspectorGUI();
OnInspectorGUIAfter();
}
private void CollectEditors()
{
var types = TypeCache.GetTypesDerivedFrom(typeof(ICustomEditor));
var list = new List<ICustomEditor>();
foreach (var e in types)
{
var editor = (ICustomEditor)Activator.CreateInstance(e);
list.Add(editor);
}
m_beforeEditors = list
.Where(t => t.Type == EditorType.Before)
.ToArray();
m_afterEditors = list
.Where(t => t.Type == EditorType.After)
.ToArray();
}
I want to add a custom test reporter to NUnit. I already did it with NUnit2, but I now need to use NUnit3.
To implement the reporter, I need to get various events from the framework, like start, end and failure of tests.
In NUnit2 I used NUnitHook to register my EventListener and it worked pretty good.
In NUnit3 I need to use the extension point mechanism, but when I add the extension point to the project, VisualStudio (2012 ultimate) immediately fails to discover the NUnit tests.
[TypeExtensionPoint(Description = "Test Reporter Extension")]
public class MyTestEventListener : ITestEventListener
{
public void OnTestEvent(string report)
{
Console.WriteLine(report);
}
}
If I remove the ITestEventListener implementation declaration from the class, it rediscovers the tests perfectly.
[TypeExtensionPoint(Description = "Test Reporter Extension")]
public class MyTestEventListener //: ITestEventListener
{
public void OnTestEvent(string report)
{
Console.WriteLine(report);
}
}
Am I doing something wrong? is there a better way to achieve it?
You don't say where you are putting this code, but I am suspecting it's in your test assembly. If so, that's not where it belongs. NUnit engine extensions get installed into the NUnit engine, so they need to be in a separate assembly. Once you have a separate assembly, you need to tell the engine where it is. Currently, you do this by creating a file of type .addins in the same directory as the engine. (You could modify the existing file, but that introduces maintenance problems in the future)
A future release will have an easier way to install addins, but they will continue to be entirely separate from your tests.
A further problem is that you are using TypeExtensionPointAttribute. I didn't notice this originally in your code and it's probably the biggest error so I'm adding this info now.
An "ExtensionPoint" is the thing you are extending. NUnit defines ExtensionPoints, while you create Extenisons to extend them. TypeExtensionPointAttribute is used inside NUnit to define extension points. It's not used by you. You use the ExtensionAttribute to define your extension.
Your extension should be defined something like this:
[Extension(Description = "Test Reporter Extension", EngineVersion="3.4")]
public class MyTestEventListener : ITestEventListener
{
public void OnTestEvent(string report)
{
Console.WriteLine(report);
}
}
You don't say what version of NUnit you are running. Test Listeners are only supported beginning with version 3.4. The EngineVersion property above is purely documentary at this point, because 3.4 is also the first version to recognize it.
There is a new writeup in the NUnit docs that may be helpful: https://github.com/nunit/docs/wiki/Writing-Engine-Extensions
VS2012 for desktop .net framework 4.5 normal windows forms applications, not WPF
Hello, I tried to search for an answer, but I'm not sure of the correct terminology. I've managed to break my code, and can't understand what I've done wrong. (i didn't think i had changed anything, but ...)
I have a solution which contains 2 projects. The first project is an executable program, and the second is a DLL, which is loaded at run time and used by the first project.
the first project contains a form, and a static class with public static strings in the same namespace. (and some other unconnected classes). specifically:
namespace project1_namespace
{
static class settings
{
public static string some_words = "some words in a string";
}
class dll_callback{
//.. some public methods here
}
dll_callback dllcallback; // instance is initialised in the code (not shown)
Form form;
public partial class frm_splash : Form
{
private void frm_splash_FormClosing(object sender, FormClosingEventArgs e)
{
// this function actually loads the DLL, ensuring its the last step
//... some error checking code removed for brevity
Assembly assembly = Assembly.LoadFrom("c:\dllpath\project2.dll");
Type type_init = assembly.GetType("project2_class");
object init = Activator.CreateInstance(type_init, form, dllcallback);
//... some error checking code removed for brevity
}// end method
}// end form class
}// end namespace
when the form is closing, the method shown above is called which calls the second projects class project2_class constructor.
in project 2, the DLL, there is:
namespace project2_namespace
{
// how did i get this working to reference "settings" class from project 1??
public class project2_class
{
public project2_class(project2_namespace.Form1 form_ref, object callback)
{
settings.some_words = "the words have changed";
//... some more stuff
}
}
}
Now, i was experimenting with some code in an entirely different part of project2, and VS2012 suddenly started refusing to compile stating:
error CS0103: The name 'settings' does not exist in the current context
the standard solution to this appears to be to add a reference to project2, but that would create circular dependencies because project 1 calls 2 as a DLL.
I really honestly don't think i had changed anything relevant to this, but also clearly I have.
looking at it, i cant see how project 2 would have access to a class in project 1 without a reference, but the list of arguments to the project2_class constructor doesn't include one, and I am absolutely positive that it hasn't changed (and I cant change it for backwards compatibility reasons).
would really appreciate help with this, as its been a lot of work to get this working.
as a side note, I've definitely learned my lesson about not using source control. and not making "how this works" comments instead of "what this does" comments.
may dynamic help you? You can not get the setting string at complie time.
I have one web application with two projects:
Project "Website"
Using CMS;
namespace Web
{
}
Project "CMS"
namespace CMS
{
public class Functions
{
}
}
Then I want to be able to use CMS.Functions.MyMethod() inside Website.Web.
Im having some problem with this.. Inside the "Website" project I have added "CMS" as a reference and I have also added Using CMS; and even tho the intellisense picks up CMS.Functions I get an error! The word CMS gets underlined blue and I get the message:
The name 'CMS' does not exist in the current context
What am I missing out? Its so weird becuase I can write CMS.Functions and the "Functions" part comes up in the intellisense but when I finish the line the word CMS gets underlined blue and I get the error even tho I got a reference and a Using statement.
From the sound of it, you want to make your Functions class methods to be static
namespace CMS
{
public class Functions
{
public static void MyMethod(){
//do stuff
}
}
}
The most likely cause is that you have not added a reference to the CMS project to your main project. That is the only time that I get the exception about the name not existing in the current context.