Is it possible in c# to get the attributes attache

2019-08-08 15:23发布

The title is a bit of a mouthful, but it's easier to see in code:

public struct MyStruct {
    public bool HasAttribute(Attribute attribute) {
        //is there any way to know?
        return ??????;
    }
}

public class MyClass {
    [SomeAttribute]
    MyStruct child;

    public MyClass() {}
}

I already know how to find the attributes on MyClass.child by getting the property info for each of its properties and then calling GetCustomAttributes, but this only works if I know that the struct instance corresponds to MyClass.child. What I'd like to do here is to figure out if a particular instance of a struct has attributes attached to it, without knowing what class contains the particular instance.

It would make sense to me if you couldn't do this for reference types because the instance could be referenced from multiple places, but shouldn't the set of attributes always be well-defined for value types?

My use case is making a library where the behavior of certain objects can be modified slightly by attaching custom attributes. If there's a more idiomatic way to approach this then I'm open to suggestions. I'm also willing to go into an unsafe context if that allows for a solution.

1条回答
冷血范
2楼-- · 2019-08-08 15:45

Sorry, but that's not possible. [SomeAttribute] is attached to the field of MyClass, and is completely unrelated to MyStruct.

There's no way to get the container of a struct for a couple of reasons:

  • It could simply be a local variable or a temporary, which means the struct could either live on the stack or in a CPU register. So, no there's no containing class there.

  • It could be contained in another struct, which would be subject to the same issue.

  • If it's contained in a class, you'd have to retrieve the container type using only the struct's address. And that would involve very nasty code, if possible at all.

    Just imagine: The address of such a struct would be the address of its containing class plus an offset. You'd have to somehow find the address of the container's vtable (assuming you could infer what looks like a vtable just from a memory address). This would be totally hazardous/unsafe and unreliable, you'd run the risk of getting access violations all the time since you'd have to dereference unknown addresses. There's just no way to get something reliable out of it.

    Oh, and you'd also have to do this while the GC could potentially move your container object around, without the possibility of pinning it since you don't know its address in the first place.

A saner approach would be to use the CLR debugging API, but at this point I'll assume you just don't want to summon Cthulhu.

I'm sure there are many other ways to achieve what you want there, but I can't be more specific without more details. Right now, I'd suggest initializing your struct explicitly, with additional parameters:

public class MyClass {
    MyStruct child = new MyStruct(doThatSpecialThingie: true);
}
查看更多
登录 后发表回答