Archive for the ‘C#’ Category

ElementName Binding In ToolTips (Borrowing a NameScope)

July 17, 2008

I had previously seen mention of the limitation that you cannot use ElementName binding within a ToolTip but I never bothered to investigate it since I didn’t have need to use it. Yesterday Josh asked me about it so I decided to look into it further. I’m going to deal with ToolTip here since that was the one he asked me about but I believe the same technique could apply to ContextMenu.

First let’s take a look at the various ways you can define a tooltip that uses ElementName in a binding and see which work.

<Window.Resources>
    <!– Shared tooltip –>
    <ToolTip x:Key=”sharedTT”>
        <TextBlock Text=”{Binding ElementName=txt, 
           Path=Text}” />
    </ToolTip>
</Window.Resources>
<DockPanel>
    <TextBox Text=”This is the tooltip text” 
            x:Name=”txt” DockPanel.Dock=”Top” />
   
    <!– 1 – explicitly provide a tooltip instance where
        the content is bound –>
    <Button Content=”Explicit ToolTip” DockPanel.Dock=”Top” >
        <ToolTipService.ToolTip>
            <ToolTip Content=”{Binding ElementName=txt, 
               Path=Text}” />
        </ToolTipService.ToolTip>
    </Button>
   
    <!– 2 – Set the tooltip to a binding –>
    <Button DockPanel.Dock=”Top” Content=”Binding”
           ToolTipService.ToolTip=”{Binding ElementName=txt, 
           Path=Text}”/>

 

    <!– 3- Set the tooltip to an object that tries to
        bind to an element outside the tooltip –>
    <Button DockPanel.Dock=”Top” Content=”Element ToolTip”>
        <ToolTipService.ToolTip>
            <TextBlock Text=”{Binding ElementName=txt, 
               Path=Text}” />
        </ToolTipService.ToolTip>
    </Button>

 

    <!– 4- Set the tooltip to an element that tries to bind
        to the value of another element within the tooltip –>
    <Button DockPanel.Dock=”Top” >
        <ToolTipService.ToolTip>
            <StackPanel>
                <TextBlock x:Name=”ttText” Text=”Foo” />
                <TextBlock Text=”{Binding ElementName=ttText, 
                   Path=Text}” />
            </StackPanel>
        </ToolTipService.ToolTip>
        Normal ToolTip
    </Button>

 

    <!– 5 – Bind to a ToolTip in Resources –>
    <Button DockPanel.Dock=”Top” 
           Content=”SharedResource ToolTip”
           ToolTipService.ToolTip=”{StaticResource sharedTT}”/>
</DockPanel>

Of all of these the only one that actually works is #2 where the ToolTip property is set to a Binding instance. Suprisingly, at least to me, is that even #4 where we are trying to bind to another element within the tooltip itself does not work.

In order to understand why these aren’t working, we need to understand how ElementName binding works. Basically, when an ElementName is used in a binding, the NameScope of the target object is used to locate the element with the specified name. If that element doesn’t have a NameScope specifically on it, the FrameworkElement.FindScope method continues up the logical tree and falls back to the inheritance context if there is no logical parent. The name scope is the object in which all named objects have been registered. So in this example, there is a NameScope created for the Window itself implicitly. Other objects also provide a namescope to prevent conflicts between names – e.g. ControlTemplate and Style. Actually in those cases, the objects themselves implement INameScope.

The ToolTip however is not part of the logical nor visual tree of the element on which it is being set. Instead, it is just the value of a property and as such it doesn’t have a way to reach the NameScope of the Window in which it was created. The reason that #2 worked is because we just set the value of the ToolTip property to a binding. Since that is a property set directly on the element, that binding has access to the namescope just as you can use in a binding for any other dependency property on the element.

So the issue we have to overcome is how to provide a way for the ToolTip to get to the NameScope of the Window. My solution was to set the NameScope of the ToolTip to a custom INameScope implementation that would get to the NameScope of the element for which the ToolTip was being used. To accomplish this, I defined a new attached property named BindableToolTip. When set, it would set the NameScope property of the tooltip (and create a tooltip if the value wasn’t a tooltip instance such as the case where you are just providing the elements that make up the content of the tooltip) to my custom INameScope implementation that would “borrow” the namescope of the element on which the tooltip was being set. I then set the real ToolTipService.ToolTip property to that tooltip instance.

I did hit one glitch along the way. The BamlRecordReader class which is used to process the compiled baml uses a stack to manage the namescopes it encounters. By the time that the BindableToolTip property change is invoked, the BamlRecordReader has already processed the ToolTip instance (through its PushContext method). So when it gets to the point where it wants to clean up its namescope stack (in its PopContext method), it finds that the tooltip now has a namescope and tries to pop an item off its stack which results in an exception because it tries to pop off more items then it pushed. To get around this, I remove the namescope from the tooltip in the Initialized event of the tooltip.

To use the new functionality, you would just replace any place you are setting the ToolTip property with the BindableToolTip property. After doing so with the sample above, every case now works. I’ve attached the sample project that defines and uses this new attached property.

Who set the DataContext?

July 14, 2008

In the course of the last month or so, several people have asked why the DataContext that they set on the form level wasn’t carried down deeper into their element tree. Since I haven’t seen any documentation going into this I’d like to go over when/why the DataContext may be explicitly set in the WPF framework.

The DataContext is an inherited property defined on FrameworkElement and on FrameworkContextElement (the latter is actually an AddOwner of the former but I’ll discuss AddOwner another day). Suffice it to say that if you set the DataContext on an element, it should/will get inherited by its descendant elements. So naturally some people will assume that if they set it on their Window/Page, that all elements within that Window/Page will get that DataContext value. Afterall they are not setting it anywhere else. Well, that is the problem. While they may not be setting it, the WPF framework does in certain situations and if you look at it you can understand why. So if anything, including within the WPF framework itself, sets the DataContext on one of the descandants of that Window/Page, then all its descandants will get its locally set DataContext instead of the one set on one of its ancestors.

Ok so when will the WPF framework actually set the DataContext? There are actually two situations that I know of in which a class in the WPF framework will set the DataContext and both relate to when it automatically generates an element for you. One is in the ItemsControl – or more accurately by the ItemContainerGenerator of an ItemsControl when a container element is generated for an element in the list. The other is in the ContentPresenter when an element is generated for its Content (e.g. based on a DataTemplate). This makes perfect sense since after all the element generated for the ItemsControl and the elements within the DataTemplate need to get access to the thing that that element is supposed to represent.

The reason this may not be noticed in normal usage is because inherited properties prefer the logical tree and therefore can “skip” over the elements that have had their DataContext set further up the visual tree between it and its logical parent. So for example, if you were to put a TextBlock into a ListBox:

    <Grid DataContext=”Foo”>
        <ListBox>
            <TextBlock Text=”{Binding}” />
        </ListBox>
    </Grid> 

At runtime, a ListBoxItem would be created to contain the TextBlock within the ListBox. The DataContext of that ListBoxItem is the TextBlock (i.e. the object it represents within the listbox). However, the DataContext of the TextBlock ends up being Foo since that is the DataContext of its logical parent (i.e. the ListBox) and would show “Foo” as its Text.

If the TextBlock were not a logical child of the listbox (e.g. if it were added to the listbox via its ItemsSource) then it would inherit the DataContext of its visual parent – which ultimately would come from the ListBoxItem.

    <Grid DataContext=”Foo”>
        <Grid.Resources>
            <x:Array x:Key=”arr” Type=”sys:Object”>
                <TextBlock Text=”{Binding}” />
            </x:Array>
        </Grid.Resources>
        <ListBox ItemsSource=”{StaticResource arr}” />
    </Grid> 

In this case, the TextBlock would have a Text value of “System.Windows.Control.TextBlock” – the ToString of the TextBlock itself since it is the DataContext of the ListBoxItem and therefore that is its DataContext.

PropertyDescriptor AddValueChanged Alternative

April 7, 2008

I’ve been meaning to write about this for a while since I’ve seen this approach mentioned lots of times on the newsgroups but have seen no mentions about the caveats. Just today I saw the same problem in some code from one of the disciples. The scenario is that you want to know when the value of a dependency property changes but you don’t have a one to one relationship with the object. For example, you have a list of items and you want to know when the IsSelected property of an item has changed.

The solution that I have seen given for this is to get to the PropertyDescriptor and use its AddValueChanged method to provide an EventHandler to receive a notification when the property has changed. Sometimes, the reply will mention/use DependencyPropertyDescriptor directly but its the same thing since that is just a derived PropertyDescriptor that provides additional information about the underlying DependencyProperty it represents. You  can get to this property descriptor in a few ways but the most common are to get it from the TypeDescriptor.GetProperties method or using the DependencyPropertyDescriptor.FromProperty.

The issue with this approach is that it will root your object so it will never get collected by the GC. There have been plenty of discussions about how hooking events (particularly static events) can root your object so I won’t go into great detail there. While it does not seem that you are hooking a static event in this case, in essence you are. When you add a handler to a property descriptor, that property descriptor stores the delegate in a hashtable keyed by the object whose property you are hooking. A delegate/handler is basically a pointer to a method on an object (or no object if its for a static method) so that means the property descriptor has a reference to your object as well as the object whose value you are watching (since that is the key into the hashtable). The property descriptors themselves are cached statically so the hashtable is kept around and therefore your object and the one you are watching are as well.

I personally like to use the Scitech memory profiler (or you can use the Microsoft CLR Profiler) when debugging memory leak issues but you can see the issue manifest itself pretty easily in this case. First we’ll do a benchmark to make sure that we can check whether the object was collected.

ListBoxItem i = new ListBoxItem();
WeakReference wr = new WeakReference(i);
i = null;
GC.Collect();
bool isAlive = wr.IsAlive;

If you run this code and check isAlive, you will see that it returns false indicating that the ListBoxItem was not referenced and was able to be collected. Now let’s try using the AddValueChanged method.

ListBoxItem i = new ListBoxItem();
WeakReference wr = new WeakReference(i);
PropertyDescriptor prop = TypeDescriptor.GetProperties(typeof(ListBoxItem))[“IsSelected”];
// the following yields the same pd
//PropertyDescriptor prop = DependencyPropertyDescriptor.FromProperty(ListBoxItem.IsSelectedProperty, typeof(ListBoxItem));
prop.AddValueChanged(i, new EventHandler(this.OnValueChanged));
i = null;
GC.Collect();
bool isAlive = wr.IsAlive;

This time isAlive returns true because the property descriptor is maintaining a reference to the ListBoxItem. Now, let’s try an alternative approach that involves creating a helper class to listen for the property change.

ListBoxItem i = new ListBoxItem();
WeakReference wr = new WeakReference(i);
PropertyChangeNotifier notifier = new PropertyChangeNotifier(i, “IsSelected”);
notifier.ValueChanged += new EventHandler(OnValueChanged);
i = null;
GC.Collect();
bool isAlive = wr.IsAlive;

In this case isAlive is false indicating that the object can be collected even though we’re still maintaining an explicit reference to the notifier. The implementation for the class – PropertyChangeNotifier – is listed below. The class is basically a simple DependencyObject that exposes 2 properties – Value returns the value of the property of the object that it is watching and PropertySource returns the object whose property it is watching. The constructor for the object takes the object whose property is to be watched for changes and the property that should be watched. This class takes advantage of the fact that bindings use weak references to manage associations so the class will not root the object who property changes it is watching. It also uses a WeakReference to maintain a reference to the object whose property it is watching without rooting that object. In this way, you can maintain a collection of these objects so that you can unhook the property change later without worrying about that collection rooting the object whose values you are watching.

public sealed class PropertyChangeNotifier :
DependencyObject,
IDisposable
{
#region Member Variables
private WeakReference _propertySource;
#endregion // Member Variables
 
#region Constructor
public PropertyChangeNotifier(DependencyObject propertySource, string path)
: this(propertySource, new PropertyPath(path))
{
}
public PropertyChangeNotifier(DependencyObject propertySource, DependencyProperty property)
: this(propertySource, new PropertyPath(property))
{
}
public PropertyChangeNotifier(DependencyObject propertySource, PropertyPath property)
{
if (null == propertySource)
throw new ArgumentNullException(“propertySource”);
if (null == property)
throw new ArgumentNullException(“property”);
this._propertySource = new WeakReference(propertySource);
Binding binding = new Binding();
binding.Path = property;
binding.Mode = BindingMode.OneWay;
binding.Source = propertySource;
BindingOperations.SetBinding(this, ValueProperty, binding);
}
#endregion // Constructor
 
#region PropertySource
public DependencyObject PropertySource
{
get 
{
try
{
// note, it is possible that accessing the target property
// will result in an exception so i’ve wrapped this check
// in a try catch
return this._propertySource.IsAlive
? this._propertySource.Target as DependencyObject
: null;
}
catch
{
return null;
}
}
}
#endregion // PropertySource
 
#region Value
/// <summary>
/// Identifies the <see cref=”Value”/> dependency property
/// </summary>
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(“Value”,
typeof(object), typeof(PropertyChangeNotifier), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnPropertyChanged)));
 
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
PropertyChangeNotifier notifier = (PropertyChangeNotifier)d;
if (null != notifier.ValueChanged)
notifier.ValueChanged(notifier, EventArgs.Empty);
}
 
/// <summary>
/// Returns/sets the value of the property
/// </summary>
/// <seealso cref=”ValueProperty”/>
[Description(“Returns/sets the value of the property”)]
[Category(“Behavior”)]
[Bindable(true)]
public object Value
{
get
{
return (object)this.GetValue(PropertyChangeNotifier.ValueProperty);
}
set
{
this.SetValue(PropertyChangeNotifier.ValueProperty, value);
}
}
#endregion //Value
 
#region Events
public event EventHandler ValueChanged;
#endregion // Events
 
#region IDisposable Members
public void Dispose()
{
BindingOperations.ClearBinding(this, ValueProperty);
}
#endregion
}

Another possible approach would be to implement your own derived WeakEventManager but I’ll leave that as an exercise for the reader. For those that choose to go this route, there is such a class – except its internal – in the PresentationFramework assembly.

0 == 0 … well, usually it does

December 20, 2007

So when does 0 not equal 0? When it is -0 and even then it depends on who you ask. According the C# specification, -0 is an acceptable value and is treated the same as positive zero in most situations and they seem to be correct because it is very hard to tell that you have a negative 0 value. Take a look at the following set of comparisons:

double zero = 0.0;

double negZero = -0.0;

 

// following all result in true values

bool areSame = zero.Equals(negZero);

bool areEqual = zero == negZero;

bool sameSign = Math.Sign(zero) == Math.Sign(negZero);

bool sameString = zero.ToString() == negZero.ToString();

When you execute the code above, the results of all the tests is true – that for these tests 0 and -0 are considered the same. However, there are cases where they are not treated the same. For example:

bool sameResult =

    Math.Atan2(zero, -1.0) == Math.Atan2(negZero, -1.0);

This is the scenario that Mike, a friend of mine at work, came across the other day. It was a bit more difficult to detect though because the values were coming from variables that were part of a series of calculations. We looked at the value of the variables in the watch window and executed the same method (Math.Atan2) in the watch window explicitly with those values (instead of the variables) and got a different result.

In this particular case, the issue may actually be a bug in that method. We’ve logged it with Microsoft so you can check the status if you’re interested. The point though is that the CLR does support this and that the values could be treated differently. So how can you tell that you are in this situation? One way is to use the BitConverter.GetBytes. If you check the bytes, you will see that the sign bit for the value is actually set indicating that its negative.

byte[] zeroBytes = BitConverter.GetBytes(zero);

byte[] negZeroBytes = BitConverter.GetBytes(negZero);

 

bool sameBytes = zeroBytes[7] == negZeroBytes[7];

One other interesting point is how you can arrive at this value without explicitly creating a negative zero as I did in the tests above. If you do calculations using doubles, it does not appear that the value will result in a -0. For example:

double one = 1.0d;

double negOne = -one + one;

double posOne = one – one;

 

byte[] negOneDBytes = BitConverter.GetBytes(negOne);

byte[] posOneDBytes = BitConverter.GetBytes(posOne);

 

// these both result in positive 0

bool sameSignBit = negOneDBytes[7] == posOneDBytes[7];

In this case, both values are positive 0. However, if you perform the same test with decimal values:

decimal one = 1.0m;

decimal negOne = -one + one;

decimal posOne = one – one;

 

double dblNegOne = Convert.ToDouble(negOne);

double dblPosOne = Convert.ToDouble(posOne);

 

byte[] negOneDBytes = BitConverter.GetBytes(dblNegOne);

byte[] posOneDBytes = BitConverter.GetBytes(dblPosOne);

 

// these have different sign bits

bool sameSignBit = negOneDBytes[7] == posOneDBytes[7];

The sign bit is set for the value that moved from a negative value towards zero and that sign bit is maintained when the value is converted to a double.

Internal And Protected Virtual

December 15, 2007

I was thinking about it this morning and the approach that I mentioned in my last post wouldn’t work if you used this from a virtual member and that member was overriden. Here’s the class structure that demonstrates this problem when using yesterday’s approach:

    public class Base

    {

        internal virtual void OnlyCallFromDerivedClasses()

        {

            Utilities.VerifyCallerIsFamily();

 

            // do something

        }

    }

 

    public class Derived : Base

    {

        internal sealed override void OnlyCallFromDerivedClasses()

        {

            base.OnlyCallFromDerivedClasses();

 

            // do something

        }

    }

 

    public class NotDerived

    {

        public void VerifyCannotCallMethod()

        {

            Derived d = new Derived();

            d.OnlyCallFromDerivedClasses();

        }

    }

Note, for brevity I will not repeat yesterday’s implementation of Utilities.VerifyCallerIsFamily. The problem can be seen if you create an instance of NotDerived and it calls OnlyCallFromDerivedClasses on an instance of B; in that case an exception will not be raised. The reason is that the direct caller of the Utilities.VerifyCallerIsFamily is override of the OnlyCallFromDerivedClasses method in class B so it appears that everything is ok.

Here’s a modified version of Utilities.VerifyCallerIsFamily that gets around this issue:

    public static class Utilities

    {

        [MethodImpl(MethodImplOptions.NoInlining)]

        [Conditional(“DEBUG”)]

        public static void VerifyCallerIsFamily()

        {

            // get the method doing the check

            StackFrame sfCallee = new StackFrame(1, false);

            MethodBase calleeMethod = sfCallee.GetMethod();

 

            int callerIndex = 2;

            StackFrame sfCaller = new StackFrame(callerIndex, false);

            MethodBase callerMethod = sfCaller.GetMethod();

 

            MethodBase callerPrevious = calleeMethod;

 

            // if the callee – the method checking whose is calling it – is

            // virtual then we need to make sure that the caller we are

            // verifying is the external method and not the derived classes

            // override of the callee method

            if (calleeMethod.IsVirtual)

            {

                while (callerMethod.IsVirtual && callerMethod is MethodInfo)

                {

                    MethodInfo baseMethod = ((MethodInfo)callerMethod).GetBaseDefinition();

 

                    // break out once we find a method that is not an override

                    // of the callee method

                    if (null == baseMethod ||

                        baseMethod.MethodHandle != callerPrevious.MethodHandle)

                        break;

 

                    callerPrevious = callerMethod;

                    callerIndex++;

                    sfCaller = new StackFrame(callerIndex, false);

                    callerMethod = sfCaller.GetMethod();

                }

            }

 

            Debug.Assert(calleeMethod.IsAssembly, “This method is meant to try and implement a scope of ‘Assembly And Family’ so the calling method should be internal.”);

 

            if (false == calleeMethod.DeclaringType.IsAssignableFrom(callerMethod.DeclaringType))

            {

                // if the caller is a nested type of the callee then

                // this is an acceptable call since nested types always have

                // access to all the members of the declaring type. this also

                // will handle the case where an anonymous method that captures

                // a local is used.

                Type callerMethodType = callerMethod.DeclaringType;

                while (callerMethodType.IsNested)

                {

                    if (calleeMethod.DeclaringType.IsAssignableFrom(callerMethodType.DeclaringType))

                        return;

 

                    // move up the declaring chain

                    callerMethodType = callerMethodType.DeclaringType;

                }

 

                const string Format = “The ‘{0}.{1}’ method is being called from ‘{2}.{3}’. It should only be called by derived types.”;

                string message = string.Format(Format,

                    calleeMethod.DeclaringType.Name,

                    calleeMethod.Name,

                    callerMethod.DeclaringType.Name,

                    callerMethod.Name);

                throw new InvalidOperationException(message);

            }

        }

    }

[Note: The section above has been modified from the original posting for this article. The loop dealing with IsNested was added to address the fact that nested classes are supposed to be allowed full access to all members defined by its nesting class.]

Now after we get the caller method, we verify that it is not an override of the callee method. If it is then we continue up the call stack until we hit a method that is not an override of the callee and perform the verification as we had been with that method.

Note, this assumes that the overriden of the member is calling the base. If it is not then it will be up to the override to make the call to VerifyCallerIsFamily.

Internal And Protected

December 15, 2007

I like to make sure that the members of the types (and the types themselves) that I define are only available to the types that need it. This is done by providing the appropriate scope. C# and VB.Net define 5 possible scopes – public, private, protected, internal (friend in VB) and internal protected (protected friend in VB). I’ll give a brief background on each so if you already know this stuff you can skip ahead:

Public

Public members are visible to all types whether they are defined in the same assembly or within another assembly. So given a class A, anyone that has an instance of A can call its Foo method.

public class A

{

   public void Foo() {}

}

Protected

Protected is sometimes referred to as Family in the CLR documentation. Basically protected means that only derived classes can access that member. So given a class A, only classes that derive from A can call its Foo method.

public class A

{

   protected void Foo() { }

}

Private

Private members are only available within that class. So given a class A, only class A can call its Foo method.

public class A

{

   private void Foo() { }

}

Assembly

Assembly scope is referred to as internal in C# and Friend in VB.Net. Assembly scoped members can be accessed by any type defined within the same assembly. So if you have assembly 1 with a class defined as follows, any other type defined within assembly 1 may access the Foo method but types defined in other assemblies cannot.

public class A

{

   internal void Foo() { }

}

Assembly Or Protected

Assembly Or Protected combines the scopes of Assembly and Protected. In C# this would be defined as internal protected and in VB.Net the member would be defined as Protected Friend. Members with this scope can be access by any type within the same assembly or types in other assemblies that derive from this type. So if you have assembly 1 with a class defined as follows, any other type defined within assembly 1 may access the Foo method and also any type that derives from A (including types defined in an assembly other than assembly 1) may access the Foo method.

public class A

{

   internal protected void Foo() { }

}

But there’s actually another scope – Assembly And Family. I used the terminology that’s used in the CLR documentation because it’s not available in C# or VB.Net. This scope is supposed to limit member access to only derived types within that assembly. Outside of that assembly or to non-derived types in the same assembly, it is as if that member doesn’t exist.

So if you have class A in assembly 1 that has a method named Foo with this scope, only classes within assembly 1 that derive from class A may access the Foo method. Personally I think this would be a useful scope to support. I even asked Jeffrey Richter at the PDC about the possibility of supporting it and he basically told me it wouldn’t happen and that I was the only person that had asked him that question. I was a little suprised by this. I spend a lot of time in reflector and there seem to be lots of cases where they could have used this type of functionality themselves.

Without this scope, you are forced to use internal instead and try to manage this via guidelines/standards. I can think of a couple of possible approaches that you could use to verify that this is the case – you could write an fxcop/static analysis rule that does the check or you could use reflection. The following method is a simple take on the latter. I’ll list the code first and then explain how it works.

    public static class Utilities

    {

        [MethodImpl(MethodImplOptions.NoInlining)]

        [Conditional(“DEBUG”)]

        public static void VerifyCallerIsFamily()

        {

            // get the method doing the check

            StackFrame sfCallee = new StackFrame(1, false);

            MethodBase calleeMethod = sfCallee.GetMethod();

 

            StackFrame sfCaller = new StackFrame(2, false);

            MethodBase callerMethod = sfCaller.GetMethod();

 

            Debug.Assert(calleeMethod.IsAssembly, “This method is meant to try and implement a scope of ‘Assembly And Family’ so the calling method should be internal.”);

 

            if (false == calleeMethod.DeclaringType.IsAssignableFrom(callerMethod.DeclaringType))

            {

                const string Format = “The ‘{0}.{1}’ method is being called from ‘{2}.{3}’. It should only be called by derived types.”;

                string message = string.Format(Format,

                    calleeMethod.DeclaringType.Name,

                    calleeMethod.Name,

                    callerMethod.DeclaringType.Name,

                    callerMethod.Name);

                throw new InvalidOperationException(message);

            }

        }

    }

The following will be our test scenario classes:

    public class Base

    {

        internal void OnlyCallFromDerivedClasses()

        {

            Utilities.VerifyCallerIsFamily();

 

            // do something

        }

    }

 

    public class Derived : Base

    {

        public void VerifyCanCallMethod()

        {

            this.OnlyCallFromDerivedClasses();

        }

    }

 

    public class NotDerived

    {

        public void VerifyCannotCallMethod()

        {

            Base b = new Base();

            b.OnlyCallFromDerivedClasses();

        }

    }

We could then test this out:

    Derived d = new Derived();

    d.VerifyCanCallMethod();

 

    NotDerived not = new NotDerived();

    not.VerifyCannotCallMethod();

The call to VerifyCanCallMethod on d will pass because Derived is a derived class and has the rights to make this call. The second call will result in an exception – “The ‘Base.OnlyCallFromDerivedClasses’ method is being called from ‘NotDerived.VerifyCannotCallMethod’. It should only be called by derived types.” – which is the behavior that we want.

Ok so how does this work. The majority of the code relies upon the use of the StackFrame class to obtain the information about the method requesting the verification (the callee) and the method that is calling that method (the caller). We have to pass in 1, since this is implemented as a helper method. Passing in 0 would return the VerifyCallerIsFamily method which we do not want.

Once we have the stackframes, we can get the MethodBase instances. These are reflection objects that provide information about the method being called. We can then use the IsAssignableFrom method to ensure that the caller is either the same type as the callee or a derived class. If it is not we raise an appropriate exception.

You may notice that I decorated the VerifyCallerIsFamily with 2 attributes. The MethodImpl attribute is used to ensure that the jitter will not inline the execution of the method. The method is a little large so its unlikely that it would but its best to make sure. We need to do this because we’re relying on getting the methods using specific indexes in the stack frame. The Conditional attribute is used to indicate that calls to this method should not be included unless the code is being compiled with the DEBUG compilation constant. In other words, we only want to do this check in a debug version. My main reason for doing this is that using a StackFrame has overhead and once we release our assembly, its really not necessary to do this check since the callee method is internal and our testing can be limited to checking calls within the same assembly.

I still hope they implement that scope in a future version of C# and VB.Net but until then this approach may help you to get close.