Question

I found something interesting while playing around with System.ComponentModel.TypeDescriptor:

public class Person
{
    public string Name { get; set; }

    public int Age { get; set; }

    public DateTime DateOfBirth { get; set; }

    public Enum Enum { get; set; }
}

public class Program
{
    public static void Main(string[] args)
    {
        var person = new Person();

        var typeDescriptionProvider = TypeDescriptor.AddAttributes(person, new DescriptionAttribute("Some description of this person"));

        // Returns no attributes if person is a *struct* instance,
        // but does return the DescriptionAttribute if person is a *class* instance
    --> var descriptionAttributes = TypeDescriptor.GetAttributes(person).OfType<DescriptionAttribute>().ToList();

        // Always returns the DescriptionAttribute
        var descriptionAttributesUsingTdp = typeDescriptionProvider.GetTypeDescriptor(person).GetAttributes().OfType<DescriptionAttribute>().ToList();

        Console.ReadLine();
    }
}

When the definition of Person is a class, the line of code with the --> finds and returns the DescriptionAttribute just fine.

When I change Person to a struct, the code does not find the DescriptionAttribute.

Why?

What is the rationale behind this difference? Is there some magic going on for reference types that is absent for value types?

I know that the line of code below the --> returns the attribute regardless of whether the instance of Person is a class or a struct. This is because the TypeDescriptionProvider returned by the AddAttributes() method call was the one that performed the addition.

Was it helpful?

Solution

Why doesn't TypeDescriptor.GetAttributes(person) return the attribute when Person is a struct?

TypeDescriptor.AddAttributes and TypeDescriptor.GetAttributes use reference equality to find objects in TypeDescriptor's internal cache. If Person is a class, then the person arguments in those two method calls reference the same instance. However, if Person is a struct, then the person arguments get boxed independently into different instances, so GetAttributes is unable to find the original person.

If person is only boxed once, then the code works as expected:

object person = new Person();  // `object` instead of `var`

Why does typeDescriptionProvider.GetTypeDescriptor(person).GetAttributes() always return the attribute?

The TypeDescriptionProvider.GetTypeDescriptor(Object) documentation isn't clear (at least to me), but note that you can apparently pass anything to typeDescriptionProvider.GetTypeDescriptor — like 42 (a struct) or "Hello, World!" (a class) — and get your attribute back:

var descriptionAttributesUsingTdp = typeDescriptionProvider.GetTypeDescriptor(42)
    .GetAttributes().OfType<DescriptionAttribute>().ToList();
// descriptionAttributesUsingTdp.Count == 1

Based on this behavior, my guess is that the typeDescriptionProvider returned by TypeDescriptor.AddAttributes(person, ...) is not associated with the person. Instead, it represents a plug-in that can add your attribute to any object, and GetTypeDescriptor is the method that does so.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top