This project has moved. For the latest updates, please go here.

how to use ExcludeHiddenMembers

Mar 10, 2014 at 3:03 PM
i have the following structure

class MyClassBase{
    private object _Control;

    public object Control {
        get { return _Control; }
    }
}
class MyClass:MyClassBase{
    // Fields...
    private Control _Control;

    public new Control Control {
        get { return _Control; }
    }

}
and i make the next call
        var propertyInfo = typeof (MyClass).Property("Control",Flags.ExcludeHiddenMembers);
        if (propertyInfo == null) throw new ArgumentNullException("propertyInfo");
but propertyinfo is null
Coordinator
Mar 10, 2014 at 3:18 PM
The most likely cause I can think of is because you pass in a custom Flags setting. You probably need to combine the specified flag with other flags to receive any results, since Fasterflect only applies default flags if you do not specify any.

Try using
Flags.InstanceAnyVisibility | Flags.ExcludeHiddenMembers
in your call to Property().
Mar 10, 2014 at 3:46 PM
hmm using the flag u suggested i get an AmbiguousMatchException

it only works if i use the same type as the base type in Myclass
    public new object Control {
        get { return _Control; }
    }
the above works fine with the extra flag. Do you think its a bug can u recommend another way to resolve it? I tried the next commit
https://github.com/expand/eXpand/commit/509e6d52229928720935a68eff4c6899e1e0f2fe

but my users complained about bad performance
Coordinator
Mar 10, 2014 at 10:20 PM
Yes, I see the problem. Fasterflect does not appear to have code to deal with the AmbiguousMatchException.

If you have checked out the code to Fasterflect, you can try editing PropertyExtensions.cs (located in the Extensions/Core folder, line 380) to this:
    var result = type.GetProperty( name, bindingFlags | Flags.DeclaredOnly );
The code did not enforce the DeclaredOnly flag, which could result in multiple properties matching the query. This should fix it (untested).

Alternatively, you can use the Properties() extension instead, as it is built to deal with multiple results (but this will be slower than locating a single, named property).

This is the code you'd use if you opt for this solution:
var pi = type.Properties("Control", Flags.InstanceAnyDeclaredOnly | Flags.ExcludeHiddenMembers).FirstOrDefault();
If you are not sure whether a property is actually declared on the type you are reflecting on, this is probably better:
var pi = type.Properties("Control", Flags.InstanceAnyVisibility | Flags.ExcludeHiddenMembers).FirstOrDefault();
Let me know if you apply the fix and how it works out.

Also, could you elaborate on the "bad performance" comment? What version are you using and what version has a problem? Is it all methods or something specific that is slower?
Coordinator
Mar 12, 2014 at 2:34 AM
I've committed the fix mentioned above (in the PropertyExtensions.cs file) and added unit tests to ensure that Fasterflect behaves properly for the above scenario.

Please let me know if this solves your problem. Also still interested in the "bad performance" comment if you have anything on that.
Mar 12, 2014 at 5:41 AM
thnks for the fix works fine in my tests i will report back when I have feedback from the users of our framework

thnks again for the support and the amazing fastreflect!
Mar 29, 2014 at 5:45 PM
Hello i now have more info on the performance thing.

I have the following call

_appearanceController.CallMethod("GetCurrentAppearanceContexts", e.View);

where GetCurrentAppearanceContexts is defined as
    internal List<string> GetCurrentAppearanceContexts(View view) {
        List<string> result = new List<string>();
        result.Add(view.Id);
        if(view is DetailView) {
            result.Add(AppearanceContext.DetailView.ToString());
        }
        else {
            result.Add(AppearanceContext.ListView.ToString());
        }
        return result;
    }
The above will be very slow do i miss something shouldn't Fastreflect take care of caching without any extra efforts?

If i replace my call to something like

_getCurrentAppearanceContexts = typeof(DevExpress.ExpressApp.ConditionalAppearance.AppearanceController).DelegateForCallMethod("GetCurrentAppearanceContexts", new[] { typeof(View) });
        for (int i = 0; i < 3000; i++){
            _getCurrentAppearanceContexts(_appearanceController, new View());
        }
it will work fast
Mar 29, 2014 at 5:57 PM
further investigation reveal that the following code will perform fast as well

for (int i = 0; i < 3000; i++){
            var delegateForCallMethod = typeof(DevExpress.ExpressApp.ConditionalAppearance.AppearanceController).DelegateForCallMethod("GetCurrentAppearanceContexts", new[] { typeof(View) });
            var currentAppearanceContexts = delegateForCallMethod(_appearanceController, e.View);    
        }
so I am really confused if the CallXXX extension method are so slow why they are first class citizen in the framework
Mar 29, 2014 at 6:20 PM
finally i understand what is happening if you explicity pass the argument types like

_appearanceController.CallMethod("GetCurrentAppearanceContexts",new[]{typeof(View)}, e.View)

it works fast else is slow do u think u can update us with a faster version ?
Coordinator
Mar 29, 2014 at 6:23 PM
I'll take a look and get back to you.. maybe later today but probably not until tomorrow.
Coordinator
Mar 29, 2014 at 6:44 PM
Meanwhile, can you put a breakpoint in Fasterflect in BaseEmitter.cs line 46 and tell me if the cache lookup is successful? It should only fail for the first invocation. If it continues to fail, there is a problem with the delegate cache. If it doesn't fail, the performance is consumed elsewhere and I'll need to run it through a profiler..
Mar 29, 2014 at 7:28 PM
how u explain that when explicity pass the Type array with the method args works fast? does not look o me like a cache issue but i will tell u the info u asked
Mar 30, 2014 at 9:35 AM
i breakpoint inside GetDelegate method and delgate2==null the 2nd time. it is then added and if u step backwards u can see the cache working but when the method is again executed normally from the application code delegate2==null again.
    internal Delegate GetDelegate()
    {
        Delegate delegate2 = cache.Get(this.CallInfo);
        if (delegate2 == null)
        {
            this.Method = this.CreateDynamicMethod();
            this.Generator = new EmitHelper(this.Method.GetILGenerator());
            delegate2 = this.CreateDelegate();
            cache.Insert(this.CallInfo, delegate2, CacheStrategy.Temporary);
        }
        return delegate2;
    }
Coordinator
Mar 31, 2014 at 10:05 PM
Edited Mar 31, 2014 at 10:08 PM
I cannot reproduce the problem here, so my best guess at whats going on is this:

When you call with a View instance only (and do not specify the type array), you are not just calling with View instances, but rather with different subclasses that are derived from View. This would cause Fasterflect to use different types in the CallInfo structure identifying the method call, which in turn would result in a cache miss. Do you think this could be the problem?

Fasterflect doesn't update the parameter types array in the CallInfo structure with data from the method being invoked, because the cache lookup occurs before the method is searched for, and so you would get nothing but cache misses.

If you replace the code snippet in your first post on the performance problem with the code below, does performance stay the same or improve?
_appearanceController.CallMethod("GetCurrentAppearanceContexts", new [] { typeof(View) }, e.View );
If this improves performance, then the cause is what I wrote above. You can either opt for specifying the base type when you know a hierarchy of types might be passed, or you can keep using the existing code: while performance might be slow at first it should improve once you have cached delegates for all of the different view types.

If it does not help, something else is broken, in which case it would help if you could make a short but complete example that I could run locally to reproduce and debug the problem.
Apr 2, 2014 at 3:51 PM
When you call with a View instance only (and do not specify the type array), you are not just calling with View instances, but rather with different subclasses that are derived from View. This would cause Fasterflect to use different types in the CallInfo structure identifying the method call, which in turn would result in a cache miss. Do you think this could be the problem?
there are only 2 classes derived from View
If you replace the code snippet in your first post on the performance problem with the code below, does performance stay the same or improve?
It is not clear what you suggesting here. Your suggestion is what i used to make my classes faster at the end. If i do not pass the args array is terribly slow. What I would expect is that fasterflect cache should be smarter. For example here we have one method with no overloads so maybe you should introduce a different cache level that does not need any types args and will work always.
Coordinator
Apr 2, 2014 at 3:58 PM
Fasterflect should internally execute the same code, regardless of whether you pass the type array or not - the only difference is that the type array is produced from the parameter values given instead of being explicit. As such, I would expect them to perform almost the same (with the explicit type being only insignificantly faster).

Can you provide me with a small test project with the slow code that I could use to reproduce the problem locally? You can email it to me directly at "firstname@lastname.com" (my name is Morten Mertner).
Apr 3, 2014 at 2:26 PM
sent
Coordinator
Apr 3, 2014 at 2:34 PM
Not seeing anything in my inbox - did you substitute firstname/lastname with my actual name info?
Apr 3, 2014 at 3:04 PM
yes i did but the mail returned and do not see any mistake can u find me at gmail as apostolis.bekiaris
Coordinator
Apr 5, 2014 at 2:02 PM
I sent an email to the given name + @gmail.com but haven't heard back.. but seriously, this is ridiculous. I've given you all the information a person needs to figure out my email address and I've had that address for decades, and continue to receive lots of email on a daily basis, so clearly you are not using the right address. If you can figure it out, I'll be happy to help resolve the issue, but don't really want to spend my time on getting emails to work.