0

Working in .Net 4.5.

I am making classes that encapsulate an ActiveX control (CadCorp SIS activeX control to be specific) and basically replicate some of the objects available internally to that control (but not externally). From the outside the properties of the internal objects have to be manipulated using an API which takes text strings.

In each class I end up writing properties for getting and setting values via the API and i's basically the same code over and over again, e.g. Control.GetInt(TargetDescripor, TargetIdentifier, PropertyName);, so I am trying to use generics to cut down code to a minimum. I now have a method like this:

public T GetPropertyValue<T>(ObjectTypes Target, string PropertyName, int TargetIdentifier = 0)

which identifies the correct API method and returns the required value.

I still have to call this method from every object with the correct descriptor and the correct property name. I have cut down on that further. For example if I get a property in one of the objects I use the following code:

public Class MyObject
{
    public bool MyObjectPropertyX
    {
        get { return this.GetProperty<bool>(); }
    }

    private const string _MyObjectPropertyX = "APICommandString";

    private T GetPropertyValue<T>([CallerMemberName] string PropertyName = null)
    {
        string apiCommand = (string)this.GetType().GetField("_" + PropertyName, BindingFlags.NonPublic | BindingFlags.Static).GetValue(this);

        // Call the method which executes the API command with the correct object
        // descriptor and get the value
    }
}

and this works just great.

Now I am wondering if it is possible in the property's getter to call the this.GetProperty<T>() with the type parameter being set automatically to the type of the property? Is that feasible? Or is what I've got now as good as it gets?

UPDATE

Also, I would be interested to know if there are any drawbacks to moving to this kind of method. I will have to make a LOT of API calls, so I am wondering if using reflection will actually slow this down compared to the original code where I called the appropriate method explicitly in each getter and setter?

yu_ominae
  • 2,975
  • 6
  • 39
  • 76
  • Have you considered generating the code, e.g., using [T4 Templates](http://msdn.microsoft.com/en-us/library/vstudio/bb126445.aspx)? – dtb Mar 28 '13 at 10:22
  • Oh, I'd never heard of that before. Thanks, I'll look into it. – yu_ominae Mar 28 '13 at 10:23
  • Take a look here: http://stackoverflow.com/a/15627799 – dtb Mar 28 '13 at 10:24
  • If you went down the T4 templates route you'd probably end up doing reflection over your CatCorp type, finding all fields then generating properties that used those fields within your class (which could do away with reflection at runtime). You could make it generate a partial (or base) class so you don't then have to write the whole class in templates. – George Duckett Mar 28 '13 at 10:29
  • @dtb Thanks. I think it's going to take me a little while to get to grips with that, but a good thing to know about anyway. Saying that, I think I would prefer getting this method to work, because it would mean less and more maintainable code overall. – yu_ominae Mar 28 '13 at 10:31
  • @GeorgeDuckett That is very tempting. Now that the idea is out I think I could generate the code using macros in excel (I can get the tabulated property data from the company's website and infer the type from the API string), which would probably be a lot faster (for me) to get the code generated. Do you think reflection like this would impose a noticeable performance hit? – yu_ominae Mar 28 '13 at 10:38
  • I'd strongly recommend T4 templates rather than doing something in excel. If you're generating the property code in T4 you'll use reflection to generate the code, you won't use reflection in the generated code. – George Duckett Mar 28 '13 at 11:09
  • @GeorgeDuckett thanks for the advice. I am not sure whether or not I'll get around to use T4 on this project (not even sure if I'll get to finish, because it's just a pet project of mine), but I'll definitely look further into this because it looks like a very nifty tool. – yu_ominae Mar 28 '13 at 23:35

1 Answers1

1

To address your first point, I don't think you will reduce the get code further without over complicating things; just specifiying the type seems fine to me.

If you want to be able to determine the property name without hardcoding a string, you can use This method with reflection.

On performance, I would say above all: Test it. If you find it is slow, then you could try caching you lookup of property actions. This code will wrap the reflected field.getValue call in a Func<string> so that the reflection lookup is not needed everytime. Bear in mind that the reflection api does some caching internally anyway, so there may be little benefit to this.

    private readonly IDictionary<String, Func<String>> _cache = new Dictionary<String, Func<String>>();

    private String GetApiCommand(String propertyName)
    {
        Func<String> command;
        if (_cache.TryGetValue(propertyName, out command))
        {
            return command();
        }

        var field = GetType().GetField("_" + propertyName, BindingFlags.NonPublic | BindingFlags.Static);//.GetValue(this);

        if (field != null)
        {
            Func<String> action = () => (String)field.GetValue(this);
            _cache[propertyName] = action;

            return action();
        }

        throw new NotSupportedException();
    }
Pondidum
  • 11,457
  • 8
  • 50
  • 69