6

I know this has several canonical answers (that I've used successfully in the past!) See https://stackoverflow.com/a/1778410/1675729 and https://stackoverflow.com/a/1565766/1675729. For reference, these methods involve using the SetValue method on the PropertyInfo of the property, or otherwise invoking the setter method with reflection, or in extreme cases, setting the backing field directly. However, none of these methods seem to be working for me now, and I'm curious if something has changed that has broken this functionality.

Consider the following:

using System;
using System.Reflection;

public class Program
{
    public static void Main()
    {
        var exampleInstance = new Example();
        var exampleType = typeof(Example);
        var fooProperty = exampleType.GetProperty("Foo"); // this works fine - the "GetSetMethod" method returns null, however

        // fails with the following:
        // [System.MethodAccessException: Attempt by method 'Program.Main()' to access method 'Example.set_Foo(Int32)' failed.]
        //fooProperty.SetValue(exampleInstance, 24);

        // same error here:
        //Run-time exception (line 14): Attempt by method 'Program.Main()' to access method 'Example.set_Foo(Int32)' failed.
        //exampleType.InvokeMember(fooProperty.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty | BindingFlags.Instance, null, exampleInstance, new object[] { 24 });
    }
}

public class Example 
{
    public int Foo { get; private set; }
}

The Foo property has a setter, it's just private. It also fails if I change the setter to protected, which seems even more bizarre, since it's no longer the C#6 initializer-only setter. This fails with both .NET 4.5 and .NET Core 2 as the runtime. What am I missing?

NWard
  • 2,016
  • 2
  • 20
  • 24
  • Private or Public? Your example shows a Public property while your question asks about a Private one. – Gusman Feb 14 '18 at 16:43
  • The property is public, the setter is private. I will clarify my question title. – NWard Feb 14 '18 at 16:44
  • 3
    I'm a little confused, the code above works fine for me. Is the `Example` class in a different assembly? – DavidG Feb 14 '18 at 16:45
  • I am also confused, hence this question. Try it: https://dotnetfiddle.net/o4JtEq – NWard Feb 14 '18 at 16:48
  • Not even setting the backing field works? – IS4 Feb 14 '18 at 16:52
  • @IllidanS4 I can't find the backing field with the usual name of `_BackingField` nor does it appear in any of the field collections in the reflection metadata. But that seems like a separate problem - I don't like relying on backing fields to set properties if I can avoid it, since they're an implementation detail that can change across runtimes and so forth – NWard Feb 14 '18 at 16:53
  • Are you running from partially trusted code? – user6144226 Feb 14 '18 at 16:55
  • No. I am running the exact code as I have provided in the question. Follow the dotnetfiddle link I provided in a comment to see it throw the exception. – NWard Feb 14 '18 at 16:56
  • 1
    @NWard It seems pretty logical to me that an online complier is not running in full-trust. As far as this link is concerned this seems like the expceted behaviour https://learn.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/security-considerations-for-reflection#accessingNormallyInaccessible – user6144226 Feb 14 '18 at 17:00
  • Does this code only not work in dotnetfiddle or do you see the same results in a local app? – DavidG Feb 14 '18 at 17:08
  • user6144226 is right - you are running this from partially trusted code which lacks permission to reflect over private members, so you have this exception. – Evk Feb 14 '18 at 17:09
  • @user6144226 You are correct - that is why the dotnetfiddle example fails. If I run that code in a local app it works, in my actual code I *am* trying to use reflection on code that's in another assembly. So this has become another question, which has to do with how .NET Core handles assembly trust. If one of you would like to post an answer that addresses the failure in the online compiler (linking to the security documentation), I think that might be valuable. – NWard Feb 14 '18 at 17:14

2 Answers2

2

I was having a similar issue (with the exception that I'm using a static property) and I was able to invoke private setter like this:

public static class Example 
{
    public static int Foo { get; private set; }
}

typeof(Example).GetProperty("Foo").SetMethod.Invoke(null, new object[] { 42});

Haven't tested with non-static though.

Alex from Jitbit
  • 53,710
  • 19
  • 160
  • 149
1

This behaviour is by design. There are some strict rules that govern the ability to abuse reflection in this way.

Accessing Members That Are Normally Inaccessible

In fact if you plan on using reflection at all, in a real life secnario the entire article might be worth a read. Security Considerations for Reflection

user6144226
  • 613
  • 1
  • 8
  • 15