简体   繁体   中英

Get custom attribute from SubClass in BaseClass (C# .NET 4.0)

Ok, edited the code for clarification:

Question: How can I access the attribute [MyAttr("...")] in TestClassOne/Two from BaseClass.TheAttribute ...?

All classes except TestClassOne/Two will be compiled in to my "core" and delivered as a dev-platform to a customer. The TestClassOne/Two is developed by the customer, so there can be no knowledge of the TestClassOne/Two in the "core".

Code below is compiled into "core" and delivered to customer as dll.

[TestMethod()]
public void AttrTest()
{
    var one = new TestClassOne();
    var attrOne = one.MyTestProperty.TheAttribute;

    var two = new TestClassTwo();
    var attrTwo = two.MyTestProperty.TheAttribute;
}

public class MyAttr : Attribute
{
    private string _test;
    public MyAttr(string test)
    {
        this._test = test;
    }
}

public class BaseClass
{
    public string TheAttribute
    {
        get { 
            // Here I would like to get the "[MyAttr("...")]" from the classes in the bottom

            return null;
        }
    }
}

public class SubClass : BaseClass
{

}

Code below is developed by customer (using my dll's)

public class TestClassOne
{
    [MyAttr("Attribute one")]
    public SubClass MyTestProperty = new SubClass();
}

public class TestClassTwo
{
    [MyAttr("Attribute two")]
    public SubClass MyTestProperty = new SubClass();
}

Edit 3:

You can walk the call stack, looking for a relevant attribute in a relevant member in a relevant class. Try this:

public class MyAttr : Attribute
{
    private string _test;
    public MyAttr(string test)
    {
        this._test = test;
    }

    public string getAttr()
    {
        return _test;
    }
}


public class BaseClass
{
    private string theString;

    public BaseClass()
    {
        StackTrace callStack = new StackTrace();

        for ( int i = 0; i < callStack.FrameCount; i++ )
        {
            Type t = callStack.GetFrame(i).GetMethod().DeclaringType;
            foreach ( MemberInfo m in t.GetMembers().Where(x => typeof(BaseClass).IsAssignableFrom(x.Type)) )
            {
                foreach ( var z in  m.GetCustomAttributes(typeof(MyAttr)) )
                {
                    MyAttr theAttr = z as MyAttr;
                    if ( z!= null )
                    {
                        theString = z.getAttr();
                        return;
                    }
                }
            }
        }
    }

    public string Test
    {
        get { 
            return theString;
        }
    }
}

This requires that your customer always initializes the SubClass member inside the class that declares it. If they start deriving TestClassOne or have it and TestClassTwo derive from a common class that initializes the member, this code will break.

With clever use of reflection, you can expand the above code to cover more use cases, but that's beyond the scope of this question.

Edit 2:

No. I'm sorry, but what you're trying to do isn't possible. There's no "normal" way for an instance of SubClass to know if it's being declared in a member field of some other object, or in an element in an array or in a temporary variable in the stack, or whatever. As such, there's no way for that instance to access the attributes of the member field that's declaring it.

(I suppose you might want to try to access the garbage collector to find out where in memory the this object lives, but that's probably way beyond the scope of this problem, and in any case, not something I know how to do.)

I suspect your problem lies elsewhere entirely. Maybe you need to require your customer to make TestClassOne and TestClassTwo derive from a common abstract class. Maybe they need to derive from BaseClass themselves. Maybe you need to add parameters to the constructor. Maybe you need to provide a different interface altogether. We can't know unless you provide more information on your specific business requirements.

Edit:

To access the attributes declared on the MyTest member, try something along these lines:

public class BaseClass
{
    public string Test
    {
        get { 
            var attr = typeof(Test).GetMembers().Where(x => x.Type == this.GetType()).First().GetCustomAttributes(true);
            return null;
        }
    }
}

This will search class Test for a member with the same type as this and look for attributes on that member.

(I don't have my Visual Studio here, to check the exact Where syntax, but it should be pretty close to that...)

Original Answer:

Your attribute is declared on the MyTest member of class Test . But, you're doing GetCustomAttributes on class SubClass itself.

Try this:

[MyAttr("apa")]
public class SubClass : BaseClass
{

}

public class Test
{
    public SubClass MyTest = new SubClass();
}

Should get you what you want.

You can get directly from type Test :

var result = typeof (Test)
               .GetField("MyTest", BindingFlags.Public | BindingFlags.Instance)
               .GetCustomAttribute<MyAttr>();

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