Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Expand supported Caller Info Attributes #351

Closed
HaloFour opened this issue Feb 10, 2015 · 8 comments
Closed

Proposal: Expand supported Caller Info Attributes #351

HaloFour opened this issue Feb 10, 2015 · 8 comments

Comments

@HaloFour
Copy link

Problem:

The currently supported caller info attributes can only provide the name of the method, the name of the source file and the line number of the call in the source file. This is fine for scenarios such as simplifying implementations of INotifyPropertyChanged. However, if using these attributed for logging the amount of information available is quite limited.

Solution:

Expand the number of supported caller info attributes to allow embedding additional diagnostic information. The following list is quite expansive to discuss/argue over the potential possibilities.

CallerColumnNumberAttribute: The column number of where the method is invoked.
CallerTypeNameAttribute: The simple name of the declaring type of the calling method.
CallerNamespaceAttribute: The namespace of the declaring type of the calling method.
CallerFullTypeNameAttribute: The full name of the declaring type of the calling method.
CallerTypeAttribute: The declaring type of the calling method. This is replaced by the compiler by ldtoken of the type followed by a call to Type.GetTypeFromHandle.
CallerMethodAttribute: The MethodBase of the calling method. This is replaced by the compiler by ldtoken of the method reference followed by a call to MethodBase.GetMethodFromHandle.

Example usage:

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace Project1 {
    public static class Program {
        private static void Foo([CallerMemberName] string memberName = null,
                                [CallerTypeName] string typeName = null,
                                [CallerNamespaceName] string namespaceName = null,
                                [CallerFullTypeName] string fullTypeName = null,
                                [CallerFilePath] string filePath = null,
                                [CallerLineNumber] int lineNumber = 0,
                                [CallerColumnNumber] int columnNumber = 0,
                                [CallerType] Type type,
                                [CallerMethod] MethodBase method)
        {
            Debug.Assert(memberName == "Main");
            Debug.Assert(typeName == "Program");
            Debug.Assert(namespaceName == "Project1");
            Debug.Assert(fullTypeName == "Project1.Program");
            Debug.Assert(filePath == "c:\\foo\\bar\\Program.cs");
            Debug.Assert(lineNumber == 29);
            Debug.Assert(columnNumber == 12);
            Debug.Assert(type == typeof(Program));
            Debug.Assert(method == typeof(Program).GetMethod("Main"));
        }

        public static void Main() {
            Foo();
        }
    }
}
@AdamSpeight2008
Copy link
Contributor

That's a lot of optional parameters, maybe time for an object?

Public Foo( [CallerInfo] As CallerInfo = null);

CallerInfo

Class CallerInfo
  Public ReadOnly MemberName   As String
  Public ReadOnly TypeName     As String
  Public ReadOnly Namespace    As String
  Public ReadOnly FullTypeName As String
  Public ReadOnly FilePath     As String
  Public ReadOnly LineNumber   As Integer
  Public ReadOnly ColumnNumber As Integer
  Public ReadOnly Type         As Type
  Public ReadOnly Method       As MethodBase
End Class

@HaloFour
Copy link
Author

Maybe. I wouldn't imagine that they would all be used in conjunction, but that could be useful as a convenience.

@ashmind
Copy link
Contributor

ashmind commented Mar 1, 2015

@HaloFour Some attributes seem redundant:

Attribute Equvalent
[CallerTypeName] CallerMethod.ReflectedType.Name
[CallerNamespace] CallerMethod.ReflectedType.Namespace
[CallerFullTypeName] CallerMethod.ReflectedType.FullName
[CallerType] CallerMethod.ReflectedType

@HaloFour
Copy link
Author

HaloFour commented Mar 6, 2015

@ashmind

That they are. Technically you wouldn't need anything beyond [CallerMethod], [CallerFilePath], [CallerLineNumber] and [CallerColumnNumber] in order to derive all of that information, and if those were the only attributes that existed then I would be completely happy. It is the existing attribute [CallerMemberName] which set the precedent for attributes only resulting in portions of the metadata and so I simply completed the story.

@304NotModified
Copy link

This would be very useful in log libraries, like NLog. We now use stacktrace for that, but those are not implemented in the new framework (yet?) https://github.com/dotnet/corefx/issues/1797

I think one object/struct would be better then a those optional parameters.

@304NotModified
Copy link

If this will be implemented with a new type (e.g. Foo([CallerInfo] ICallerInfo)), it would be also nice if that call has preference over Foo(). AFAIK this is now not the case, so a change in the caller attributes is a breaking change (not binary backwards-compatible).

@Licshee
Copy link

Licshee commented Feb 25, 2016

I suppose CallerTypeName & CallerType etc. should be named CallerOwnerTypeName & CallerOwnerType and so on...

And CallerType etc. or additional CallerMemberType etc. should be of the method return type (in case of property accessor, it has to be the property type).

@gafter
Copy link
Member

gafter commented Mar 27, 2017

This has been moved to dotnet/csharplang#87

@gafter gafter closed this as completed Mar 27, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants