简体   繁体   中英

Get an attribute for a class containing a property with a Lazy initializtion

I don't think what I'm trying to do is possible. I have a property that is lazy initialized. Within the constructor I want to get the value of an attribute on the class that contains the property. I have a minimal example below.

public class Demo
{
    private Lazy<InternalDemo> data;

    public Demo(*stuff*)
    {
        data = new Lazy<InternalDemo>(*stuff*);
    }

    public string GetDetails()
    {
        return data.Value.Details;
    }

    private class InternalDemo
    {
        public string Details { get; set; }
        public InternalDemo()
        {
            //Details = SomeAttribute.Text
        }
    }
}

[SomeAttribute("Here are details")]
public static class DemoContainer
{
    public static Demo Things { get; } = new Demo();
}

[SomeAttribute("Here are more details")]
public static class DemoContainer2
{
    public static Demo2 Things { get; } = new Demo();
}

//Value is referenced via 
DemoContainer.Demo.GetDetails() //"Here are details"
DemoContainer2.Demo2.GetDetails() //"Here are more details"
//etc

The DemoContainer class is just an example, there are lots of classes containing Demo properties so the type with the attribute is not a constant. The property names are also not guaranteed to be unique throughout the application.

When this is not Lazy , I can use reflection to walk the stack until it finds the class with SomeAttribute defined, however with Lazy , DemoContainer isn't part of the stack.

I know that I could pass in the type of DemoContainer , or ever the value of SomeAttribute to the Demo constructor, but the purpose of this attribute was to avoid having to do so. The properties are static because they're part of a caching mechanism, but I didn't want to initialize them until they're actually used.

Also, I don't want to add reflection outside of the Lazy because there are lots of these static properties and I don't want a large overhead on initial load. I've already tested this.

I suspect I'll end up passing the attribute data as a string to the constructor, but I wanted to make sure there wasn't something else I could do to make this lookup work. It doesn't matter if it's an inefficient way to do it, either, since it will only run on first use.

When you call DemoContainer.Demo , it returns an instance of Demo that doesn't "know" where it came from. Nothing references back to the DemoContainer class, which means you can't access the attribute of that class.

Although the instance of Demo doesn't know where it came from, you know where it came from because you're calling it. So at whatever point you're calling DemoContainer.Demo , you could also read the attribute from DemoContainer :

var someAttribute = typeof(DemoContainer).GetCustomAttribute(typeof(SomeAttributeAttribute))
    as SomeAttributeAttribute;
var attributeValue = someAttribute?.AttributeValue;

But if that's how you want to use whatever that value is, this would be much easier:

public static class DemoContainer
{
    public const string Details = "Here are details";
    public static Demo Things { get; } = new Demo();
}

In other words, why read it from an attribute at all?

But even better, if you want the originator of the object to somehow include information in the object, you can just do that through the object's constructor.

public static class DemoContainer
{
    public static Demo Things { get; } = new Demo("Here are details");
}

That seems like the most intuitive way to get the desired result.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM