Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Congratulations! You've hit a leaky abstraction. :-/</p> <p>The problem is this: <a href="https://www.securecoding.cert.org/confluence/display/java/MET05-J.+Ensure+that+constructors+do+not+call+overridable+methods" rel="noreferrer">for better or worse</a>, virtual method calls from constructors invoke the most derived method implementation. C# is the same as Java in this respect; consider the following program:</p> <pre><code>using System; class Base { public Base () { Console.WriteLine ("Base..ctor"); M (); } public virtual void M () { Console.WriteLine ("Base.M"); } } class Derived : Base { public Derived () { Console.WriteLine ("Derived..ctor"); } public override void M () { Console.WriteLine ("Derived.M"); } } static class Demo { public static void Main () { new Derived (); } } </code></pre> <p>When run, the output is:</p> <pre><code>Base..ctor Derived.M Derived..ctor </code></pre> <p>That is, the <code>Derived.M()</code> method is invoked before the <code>Derived</code> constructor has executed.</p> <p>In Mono for Android, things get more...complicated. The <a href="http://docs.xamarin.com/android/advanced_topics/architecture/android_callable_wrappers" rel="noreferrer">Android Callable Wrapper (ACW)</a>'s constructor is invoked by Java and is responsible for creating the <a href="http://docs.xamarin.com/android/advanced_topics/garbage_collection#Cross-VM_Object_Collections" rel="noreferrer">peer C# instance and mapping the Java instance to the C# instance</a>. <em>However</em>, if a virtual method is invoked from the Java constructor, then the method will be dispatched <em>before there is a C# instance to invoke the method upon!</em></p> <p>Let that sink in a bit.</p> <p>I don't know which method is triggering the scenario for your specific code (the code fragment you provided works fine), but we do have a sample which hits this scenario: <a href="https://github.com/xamarin/monodroid-samples/blob/master/ApiDemo/Text/LogTextBox.cs#L26" rel="noreferrer">LogTextBox</a> <a href="https://github.com/xamarin/monodroid-samples/blob/master/ApiDemo/Text/LogTextBox.cs#L45" rel="noreferrer">overrides</a> the <a href="http://androidapi.xamarin.com/?link=P:Android.Widget.TextView.DefaultMovementMethod" rel="noreferrer">TextView.DefaultMovementMethod</a> property, and the <a href="https://github.com/android/platform_frameworks_base/blob/gingerbread-release/core/java/android/widget/TextView.java#L366" rel="noreferrer"><code>TextView</code> constructor invokes the <code>getDefaultMovementMethod()</code> method</a>. The result is that Android tries to invoke <code>LogTextBox.DefaultMovementMethod</code> before a <code>LogTextBox</code> instance even exists.</p> <p>So what does Mono for Android do? Mono for Android created the ACW, and thus knows which C# <em>type</em> the <code>getDefaultMovementMethod()</code> method should be delegated to. What it doesn't have is an instance, because one hasn't been created. So Mono for Android creates an instance of the appropriate type...via the <code>(IntPtr, JniHandleOwnership)</code> constructor, and generates an error if this constructor cannot be found.</p> <p>Once the (in this case) <code>TextView</code> constructor finishes executing, the <code>LogTextBox</code>'s ACW constructor will execute, at which point Mono for Android will go "aha! we've already created a C# instance for this Java instance", and will <em>then</em> invoke the appropriate constructor on the already created instance. Meaning that for a single instance, two constructors will be executed: the <a href="https://github.com/xamarin/monodroid-samples/blob/master/ApiDemo/Text/LogTextBox.cs#L28" rel="noreferrer"><code>(IntPtr, JniHandleOwnership)</code> constructor</a>, and (later) the <a href="https://github.com/xamarin/monodroid-samples/blob/master/ApiDemo/Text/LogTextBox.cs#L41" rel="noreferrer"><code>(Context, IAttributeSet, int)</code> constructor</a>.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload