Question

I am learning about how to use Custom Attributes to add meta info to my parameter classes. I am following an example found in a textbook titled "Professional C# 5.0".

Below is the complete program embedded in a test fixture. The Assert statement should return a value larger than 0; but it does not. I'm baffled as to why. Please assist. The code below is self contained: create a new class library project and make sure you have a reference to NUnit to run the unit test. On the other hand if you are an expert you can likely just read the code and give me feedback.

using System;
using System.Reflection;
using NUnit.Framework;

namespace GameDesigner.Sandbox.TestFixtures
{
    [TestFixture]
    internal class DeclarativeAttributesTestFixture
    {
        [Test]
        public void UseReflectionToFindNumericAttributes()
        {
            Assembly theAssembly = typeof (PhaseState).Assembly;

            Assert.AreEqual("GameDesigner.Sandbox, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
                            theAssembly.FullName);

            Attribute[] supportingAttributes = Attribute.GetCustomAttributes(theAssembly, typeof(OptimizableNumeric));

            Assert.IsTrue(supportingAttributes.Length > 0, "supportingAttributes was length: " + supportingAttributes.Length);
        }
    }


    public class PhaseState
    {
        public PhaseState(double temperatue, int pressure, string state)
        {
            Temperature = temperatue;
            Pressure = pressure;
            State = state;
        }

        [OptimizableNumeric(0.0, 300.0, 1.0)] public double Temperature;

        [OptimizableNumeric(1.0, 10.0, 1.0)] public int Pressure;

        [OptimizableNominal(new string[] {"solid", "liquid", "gas"})] public string State;
    }

    [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
    public class OptimizableNumeric : Attribute
    {
        private readonly double _start;
        private readonly double _stop;
        private readonly double _stepSize;

        public OptimizableNumeric(double start, double stop, double stepSize)
        {
            _stepSize = stepSize;
            _stop = stop;
            _start = start;
        }

        public double Start
        {
            get { return _start; }
        }

        public double Stop
        {
            get { return _stop; }
        }

        public double StepSize
        {
            get { return _stepSize; }
        }
    }

    [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
    public class OptimizableNominal : Attribute
    {
        private readonly string[] _nominalList;


        public OptimizableNominal(string[] nominalList)
        {
            _nominalList = nominalList;
        }

        public string[] NominalList
        {
            get { return _nominalList; }
        }
    }
}

I have tried many different examples of how to retrieve the custom attributes and none of them have generated results. As I am copying from the textbook without any understanding of what I am doing the code is hard for me to diagnose.

Was it helpful?

Solution

Attribute[] GetCustomAttributes(Assembly element, Type attributeType) method returns array of the custom attributes applied to an assembly. Attributes applied to assembly look like

[assembly: AssemblyCompany("Microsoft")]

Your attribute is not applied to assembly. Use following code to get custom attributes applied to State field:

var memberInfo = typeof(PhaseState).GetField("State");
Attribute[] supportingAttributes = 
  Attribute.GetCustomAttributes(memberInfo, typeof(OptimizableNominalAttribute));

If you want to check all public members in assembly which have this attribute, you can use following query:

var attributeType = typeof(OptimizableNominalAttribute);

var supportingAttributes = theAssembly.GetTypes()
          .SelectMany(t => t.GetMembers()) // you can pass binding flags here
          .SelectMany(m => Attribute.GetCustomAttributes(m, attributeType));

Query syntax:

var supportingAttributes = 
      from t in theAssembly.GetTypes()
      from m in t.GetMembers()
      from a in Attribute.GetCustomAttributes(m, attributeType)
      select a;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top