4

I'm producing a serializer in C# (.NET 4.5, VS 2013), and I'm using an attribute to control serialization metadata, such as the name to store a member under for reading and writing. Since I don't want to write out the member name as an argument for the attribute each time, I'm trying to use CallerMemberName.

For properties, it works fine: the property name is passed when the constructor gets called, and the attribute lets me assign the property value in deserialization.

For fields, for whatever reason, CallerMemberName refuses to work. Instead, I'm getting the default string.Empty every time, even when the other argument parameters are passing correctly.

My current code for testing this is:

class AttributeTest
{
    [VariableAttribute(true)]
    public string testField;

    [VariableAttribute(false)]
    public string testProperty { get; set; }

    static void Main(string[] args)
    {
        Console.WriteLine("spawning");
        AttributeTest test = new AttributeTest();
        test.testField = "sdasd";
        foreach (MemberInfo info in typeof (AttributeTest).GetMembers().Where(x => x.GetCustomAttribute(typeof(VariableAttribute)) != null))
        {

            //Console.WriteLine(info.Name);
            VariableAttribute attr = (VariableAttribute)info.GetCustomAttribute(typeof (VariableAttribute));
            Console.WriteLine(attr.testStore);
        }

        //Console.WriteLine(typeof(AttributeTest).GetMember("testField")[0].GetCustomAttributes().ElementAt(0));

        test.testProperty = "falsdka";
        Console.ReadKey();
    }
}

[AttributeUsage(AttributeTargets.Field|AttributeTargets.Property)]
public class VariableAttribute : System.Attribute
{
    public bool testStore;

    public VariableAttribute(bool test = true, [CallerMemberName] string caller = "")
    {
        testStore = test;
        Console.WriteLine(caller);
    }
}

I've tested it with the field receiving no arguments, with the field receiving an argument to make sure the constructor is being called, with the field throwing a constructor exception to make doubly sure the constructor is being called, and I can't figure out what I'm doing wrong.

Isaac van Bakel
  • 1,772
  • 10
  • 22
  • Docs.ms needs a doc fix. The "Caller Information" article states that if a "call occurs within [an] attribute constructor [then the] member name result [is] the name of the member to which the attribute is applied". Seems to leave it open that it might work for fields, but I can also confirm that it does not. – William Jul 20 '18 at 20:51

1 Answers1

3

As MSDN states, quote:

Allows you to obtain the method or property name of the caller to the method.

So you'll have to find another way to do what you're doing, or stick with properties.

Alex Seleznyov
  • 905
  • 6
  • 18
  • Makes sense, since semantically a field can not call anything- _Caller_ in _CallerMemberName_ is not applicable to it. – Eyal Perry Jul 06 '16 at 21:00
  • The call to the constructor isn't explicit in either the field or the property, however - and the attribute constructor IS being called. I suppose the real mystery is what's calling it in the case of the field. Just one more thing to throw on Microsoft's sickly syntactic sugar pile. – Isaac van Bakel Jul 07 '16 at 09:24