The question
Is there a way to get the position in code of where an attribute has been used, or the location where a member variable has been declared?
I am not searching for a workaround for this problem, only for a simple answer if this is technically possible or not.
Some background information
I have defined an attribute that connects a member to a VisualElement in a Unity UI Document using the parameters provided to the Attribute. Here's an example:
[Query("button-upvote")]
private Button _buttonUpvote;
Now in some situations the element does not exist, which means _buttonUpvote
cannot be resolved, maybe because there is a typo, in which case I want to log a warning to the Unity console. In this warning I get a stack trace, but I don't get a stack trace that leads me to the attribute or the member in question as in the above example, it leads me to the code that logged the warning, which is totally unrelated to the actual error in this case. I would like to include the position where the Query
attribute has been used, in the warning log.
CodePudding user response:
Not sure if it possible in Unity but in latest .NET compilers you can use CallerFilePathAttribute
and CallerLineNumberAttribute
:
public class MyAttribute : Attribute
{
public string Path { get; }
public int Line { get; }
public MyAttribute(string someVal, [CallerFilePath] string path = "",[CallerLineNumber] int line = 0)
{
Path = path;
Line = line;
}
}
class MyClass
{
[My("test")]
public int Test { get; set; }
}
var myAttribute = typeof(MyClass).GetProperty(nameof(MyClass.Test)).GetAttribute<MyAttribute>();
Console.WriteLine($"{myAttribute?.SomeVal} - {myAttribute?.Path} - {myAttribute?.Line}"); // prints something like: test - D:\Projects\TestApp\SoAnswers.NET6\CallerLineAttibuteTests.cs - 19
CodePudding user response:
Custom attributes by themselves are just metadata. If you pass around an attribute instance: no, it doesn't automatically have access to the element it is declared around - however, you could pass around an attribute instance along with the member info!
However, an alternative approach here might be to move the problem to build-time rather than run-time, via a Roslyn analyzer that identifies that attribute and performs the validation you need right there in the IDE. This gives a much better feedback loop to the consumer, but would require you to learn a completely different API (Roslyn is very different to reflection).