Accessing a member on Form may cause a runtime exception because it
is a field of a marshal-by-reference class
I know what this warning is and know how to solve it.
My question is why could this cause a runtime error?
You are probably talking about warning CS1690, repro code:
public class Remotable : MarshalByRefObject {
public int field;
}
public class Test {
public static void Run() {
var obj = new Remotable();
// Warning CS1690:
Console.WriteLine(obj.field.ToString());
}
}
In a remoting scenario, the Test.Run method will work with a proxy of the Remotable object. Building a proxy for a property, method or event isn't much of a problem, just a matter of creating a MethodTable that contains the substitutes. Fields are a problem however, there's nothing to 'hook'. For a MBRO, the JIT compiler no longer generates code to access the field directly, it injects a call to a helper method built into the CLR, JIT_GetField32() in this case.
That helper checks if the object is a proxy and uses the remoting plumbing to obtain the remote value if that's the case. Or just accesses the field directly if it isn't. Making the ToString() call however requires the value to be boxed. That's a problem, boxing isolates the value from the proxy. There is no way to ensure that the boxed value is always an accurate copy of the remoted value. Calling JIT_GetField32() again whenever the ToString() method uses the value to format the string isn't possible.
The workaround for CS1690 is simple, beyond wrapping the field with a property, just copy the field value in a local variable. Now it is crystal clear that the code is working with a copy and there is never a surprise so the compiler won't have to emit a warning.
public static void Run() {
var obj = new Remotable();
var value = obj.field;
Console.WriteLine(value.ToString()); // No warning
}
In addition to the suggestion from #hans-passant, I think another useful way to fix this warning is by turning your field into a property.
public class Remotable : MarshalByRefObject {
public int field;
}
could become
public class Remotable : MarshalByRefObject {
public int field { get; set }
}
and you no longer get any warnings! (Hans Passant already has an excelent explanation for this, see his post)
Obviously, you can not always alter the object you are working with (example: WinForms where the fields are generated for you) so you might have to fallback to using a temporary variable.
Or you can write:
var obj = new Remotable();
Console.WriteLine(((int) obj.field).ToString()); // No warning
Here you take your own responsibility for that cast (unboxing).
If the other side of the marshalled object has died, it will throw a runtime error stating that the referenced object does not exist anymore.
Related
First let me try to explain my situation.
Since we can not add a string value to an enumeration and I am NOT adding a custom parameter class in order to store and read it (for performance reasons since reflection is involved if I use something like: public class StringValueAttribute : Attribute), so I decided to use the following type of class:
public class Permissions
{
public const string X1 = "X1";
public const string X2 = "X2";
public const string X3 = "X3";
....
public const string X43 = "CAN_HAVE A LONG NAME AND NOT FOLLOWING A PATTERN";
}
Now I want to create a method that will receive a string as a parameter. However, I want to force the programmer to use only strings from the class Permissions.
If I would have used an enumeration, this would not be a problem since the method parameter type is explicity defined.
When we are working with generics we can implement this type of constrains.
Is there anything "LIGHT/FAST" that I am not aware that allows me to do this in my case?
I've been in this situation before many times. I almost always went with the struct approach.
First you define a struct like so:
public struct Permission : IEquatable<Permission>, IEquatable<string>
{
private readonly string key;
private Permission(string key)
{
this.key = key;
}
// implement Equals, GetHashCode, IEquatable...
}
Then you can just declare all the permissions you want to have as static members of the struct.
public class Permission
{
// ...
public static readonly First = new Permission("First");
}
Now, using struct as opposed to class has one major benefit and one major drawback:
Pro: No heap allocation needed, no a pointer dereference. It is as fast as it can be.
Cons: Even though we declared the constructor private structs always have an implicit default constructor. It is invisible but arrays are default initialized with it and is does default(T).
If you decide to go with a struct, it's highly advisable to add the following method/property:
public bool IsEmpty
{
get { return this.key == null; }
}
If you decide on the class approach, the allocation is mostly saved as I don't assume you will be allocating new instances apart of the ones already declared as static members, so the drawback is really the extra pointer.
No, there's nothing that does this within the language. If you can possibly avoid this situation, it would be good to do so. When we have more context, we may be able to suggest alternatives.
If you really have to use this approach, I would suggest first adding execution-time validation to the method, so that if an invalid value is passed in, you'll find out immediately rather than proceeding with invalid data.
Secondly, you could write a Roslyn analyzer to find all invocations of your method, and check that the argument is of the appropriate form. However, that could cause a problem if you have a situation like this:
public void Foo()
{
FooImpl(Permissions.X1);
DoSomethingElse();
}
private void FooImpl(string permission)
{
RealMethodWithChecking(permission);
}
At that point, your Roslyn analyzer would go off because the argument to RealMethodWithChecking doesn't come directly from Permissions - but it's a parameter which itself comes from Permissions. Whether or not this is a problem, and how you decide to address it, will very much depend on context.
I just ran into the strangest thing and I'm a bit mind = blown at the moment...
The following program compiles fine but when you run it you get a RuntimeBinderException when you try to read Value. 'object' does not contain a definition for 'Value'
class Program
{
interface IContainer
{
int Value { get; }
}
class Factory
{
class Empty : IContainer
{
public int Value
{
get { return 0; }
}
}
static IContainer nullObj = new Empty();
public IContainer GetContainer()
{
return nullObj;
}
}
static void Main(string[] args)
{
dynamic factory = new Factory();
dynamic container = factory.GetContainer();
var num0 = container.Value; // WTF!? RuntimeBinderException, really?
}
}
Here's the mind blowing part. Move the nested type Factory+Empty outside of the Factory class, like so:
class Empty : IContainer
{
public int Value
{
get { return 0; }
}
}
class Factory...
And the program runs just fine, anyone care to explain why that is?
EDIT
In my adventure of coding I of course did something I should have thought about first. That's why you see me rambling a bit about the difference between class private and internal. This was because I had set the InternalsVisibleToAttribute which made my test project (which was consuming the bits in this instance) behave the way they did, which was all by design, although alluding me from the start.
Read Eric Lippert's answer for a good explanation of the rest.
What caught me really of guard was that the dynamic binder takes the visibility of the type of the instance in mind. I have a lot of JavaScript experience and as a JavaScript programmer where there really isn't such a thing as public or private, I was completely fooled by the fact that the visibility mattered, I mean after all, I was accessing this member as if it was of the public interface type (I thought dynamic was simply syntactic sugar for reflection) but the dynamic binder cannot make such an assumption unless you give it a hint, using a simple cast.
The fundamental principle of "dynamic" in C# is: at runtime do the type analysis of the expression as though the runtime type had been the compile time type. So let's see what would happen if we actually did that:
dynamic num0 = ((Program.Factory.Empty)container).Value;
That program would fail because Empty is not accessible. dynamic will not allow you to do an analysis that would have been illegal in the first place.
However, the runtime analyzer realizes this and decides to cheat a little. It asks itself "is there a base class of Empty that is accessible?" and the answer is obviously yes. So it decides to fall back to the base class and analyzes:
dynamic num0 = ((System.Object)container).Value;
Which fails because that program would give you an "object doesn't have a member called Value" error. Which is the error you are getting.
The dynamic analysis never says "oh, you must have meant"
dynamic num0 = ((Program.IContainer)container).Value;
because of course if that's what you had meant, that's what you would have written in the first place. Again, the purpose of dynamic is to answer the question what would have happened had the compiler known the runtime type, and casting to an interface doesn't give you the runtime type.
When you move Empty outside then the dynamic runtime analyzer pretends that you wrote:
dynamic num0 = ((Empty)container).Value;
And now Empty is accessible and the cast is legal, so you get the expected result.
UPDATE:
can compile that code into an assembly, reference this assembly and it will work if the Empty type is outside of the class which would make it internal by default
I am unable to reproduce the described behaviour. Let's try a little example:
public class Factory
{
public static Thing Create()
{
return new InternalThing();
}
}
public abstract class Thing {}
internal class InternalThing : Thing
{
public int Value {get; set;}
}
> csc /t:library bar.cs
class P
{
static void Main ()
{
System.Console.WriteLine(((dynamic)(Factory.Create())).Value);
}
}
> csc foo.cs /r:bar.dll
> foo
Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:
'Thing' does not contain a definition for 'Value'
And you see how this works: the runtime binder has detected that InternalThing is internal to the foreign assembly, and therefore is inaccessible in foo.exe. So it falls back to the public base type, Thing, which is accessible but does not have the necessary property.
I'm unable to reproduce the behaviour you describe, and if you can reproduce it then you've found a bug. If you have a small repro of the bug I am happy to pass it along to my former colleagues.
I guess, at runtime, container method calls are just resolved in the private Empty class, which makes your code fail. As far as I know, dynamic can not be used to access private members (or public members of private class)
This should (of course) work :
var num0 = ((IContainer)container).Value;
Here, it is class Empty which is private : so you can not manipulate Empty instances outside of the declaring class (factory). That's why your code fails.
If Empty were internal, you would be able to manipulate its instances accross the whole assembly, (well, not really because Factory is private) making all dynamic calls allowed, and your code work.
I just ran into the strangest thing and I'm a bit mind = blown at the moment...
The following program compiles fine but when you run it you get a RuntimeBinderException when you try to read Value. 'object' does not contain a definition for 'Value'
class Program
{
interface IContainer
{
int Value { get; }
}
class Factory
{
class Empty : IContainer
{
public int Value
{
get { return 0; }
}
}
static IContainer nullObj = new Empty();
public IContainer GetContainer()
{
return nullObj;
}
}
static void Main(string[] args)
{
dynamic factory = new Factory();
dynamic container = factory.GetContainer();
var num0 = container.Value; // WTF!? RuntimeBinderException, really?
}
}
Here's the mind blowing part. Move the nested type Factory+Empty outside of the Factory class, like so:
class Empty : IContainer
{
public int Value
{
get { return 0; }
}
}
class Factory...
And the program runs just fine, anyone care to explain why that is?
EDIT
In my adventure of coding I of course did something I should have thought about first. That's why you see me rambling a bit about the difference between class private and internal. This was because I had set the InternalsVisibleToAttribute which made my test project (which was consuming the bits in this instance) behave the way they did, which was all by design, although alluding me from the start.
Read Eric Lippert's answer for a good explanation of the rest.
What caught me really of guard was that the dynamic binder takes the visibility of the type of the instance in mind. I have a lot of JavaScript experience and as a JavaScript programmer where there really isn't such a thing as public or private, I was completely fooled by the fact that the visibility mattered, I mean after all, I was accessing this member as if it was of the public interface type (I thought dynamic was simply syntactic sugar for reflection) but the dynamic binder cannot make such an assumption unless you give it a hint, using a simple cast.
The fundamental principle of "dynamic" in C# is: at runtime do the type analysis of the expression as though the runtime type had been the compile time type. So let's see what would happen if we actually did that:
dynamic num0 = ((Program.Factory.Empty)container).Value;
That program would fail because Empty is not accessible. dynamic will not allow you to do an analysis that would have been illegal in the first place.
However, the runtime analyzer realizes this and decides to cheat a little. It asks itself "is there a base class of Empty that is accessible?" and the answer is obviously yes. So it decides to fall back to the base class and analyzes:
dynamic num0 = ((System.Object)container).Value;
Which fails because that program would give you an "object doesn't have a member called Value" error. Which is the error you are getting.
The dynamic analysis never says "oh, you must have meant"
dynamic num0 = ((Program.IContainer)container).Value;
because of course if that's what you had meant, that's what you would have written in the first place. Again, the purpose of dynamic is to answer the question what would have happened had the compiler known the runtime type, and casting to an interface doesn't give you the runtime type.
When you move Empty outside then the dynamic runtime analyzer pretends that you wrote:
dynamic num0 = ((Empty)container).Value;
And now Empty is accessible and the cast is legal, so you get the expected result.
UPDATE:
can compile that code into an assembly, reference this assembly and it will work if the Empty type is outside of the class which would make it internal by default
I am unable to reproduce the described behaviour. Let's try a little example:
public class Factory
{
public static Thing Create()
{
return new InternalThing();
}
}
public abstract class Thing {}
internal class InternalThing : Thing
{
public int Value {get; set;}
}
> csc /t:library bar.cs
class P
{
static void Main ()
{
System.Console.WriteLine(((dynamic)(Factory.Create())).Value);
}
}
> csc foo.cs /r:bar.dll
> foo
Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:
'Thing' does not contain a definition for 'Value'
And you see how this works: the runtime binder has detected that InternalThing is internal to the foreign assembly, and therefore is inaccessible in foo.exe. So it falls back to the public base type, Thing, which is accessible but does not have the necessary property.
I'm unable to reproduce the behaviour you describe, and if you can reproduce it then you've found a bug. If you have a small repro of the bug I am happy to pass it along to my former colleagues.
I guess, at runtime, container method calls are just resolved in the private Empty class, which makes your code fail. As far as I know, dynamic can not be used to access private members (or public members of private class)
This should (of course) work :
var num0 = ((IContainer)container).Value;
Here, it is class Empty which is private : so you can not manipulate Empty instances outside of the declaring class (factory). That's why your code fails.
If Empty were internal, you would be able to manipulate its instances accross the whole assembly, (well, not really because Factory is private) making all dynamic calls allowed, and your code work.
Please explain the following error on struct constructor. If i change struct to class
the erros are gone.
public struct DealImportRequest
{
public DealRequestBase DealReq { get; set; }
public int ImportRetryCounter { get; set; }
public DealImportRequest(DealRequestBase drb)
{
DealReq = drb;
ImportRetryCounter = 0;
}
}
error CS0188: The 'this' object cannot be used before all of its fields are assigned to
error CS0843: Backing field for automatically implemented property
'DealImportRequest.DealReq' must be fully assigned before control is returned to the caller. Consider calling the default constructor from a constructor initializer.
As the error message recommends, you can resolve this by calling the default constructor from a constructor initializer.
public DealImportRequest(DealRequestBase drb) : this()
{
DealReq = drb;
ImportRetryCounter = 0;
}
From the language specification:
10.7.3 Automatically implemented properties
When a property is
specified as an automatically
implemented property, a hidden backing
field is automatically available for
the property, and the accessors are
implemented to read from and write to
that backing field. [...] Because the
backing field is inaccessible, it can
be read and written only through the
property accessors, even within the
containing type. [...] This
restriction also means that definite
assignment of struct types with
auto-implemented properties can only
be achieved using the standard
constructor of the struct, since
assigning to the property itself
requires the struct to be definitely
assigned. This means that user-defined
constructors must call the default
constructor.
The other (more verbose) alternative, of course, is to manually implement the properties and set the backing fields yourself in the constructor.
Do note that the struct you have there is mutable. This is not recommended. I suggest you either make the type a class (your compilation problems should go away immediately) or make the type immutable. The easiest way to accomplish this, assuming the code you have presented is the entire struct, would be to make the setters private (get; private set;). Of course, you should also make sure that you don't add any mutating methods to the struct afterwards that rely on private access to modify the fields. Alternatively, you could back the properties with readonly backing fields and get rid of the setters altogether.
The code you have is equivalent to the following code:
public struct DealImportRequest
{
private DealRequestBase _dr;
private int _irc;
public DealRequestBase DealReq
{
get { return _dr; }
set { _dr = value; }
}
public int ImportRetryCounter
{
get { return _irc; }
set { _irc = value; }
}
/* Note we aren't allowed to do this explicitly - this is didactic code only and isn't allowed for real*/
public DealImportRequest()
{
this._dr = default(DealRequestBase); // i.e. null or default depending on whether this is reference or value type.
this._irc = default(int); // i.e. 0
}
public DealImportRequest(DealRequestBase drb)
{
this.DealReq = drb;
this.ImportRetryCounter = 0;
}
}
Now, all I have done here is remove the syntactic sugar that:
Implements automatic properties.
Works out which members are dealt with relative to this.
Gives all structs a default no-parameter constructor.
The first two are optional (you could write them explicitly if you wished) but the third is not - we aren't allowed to write our own code for a struct's parameterless constructor, we have to go with one that works like the one in the code above being given to us automatically.
Now, looked at here, suddenly the meaning of the two errors becomes clear - your constructor is implicitly using this before it's fields are assigned (error 188) and those fields are those backing the automatic properties (error 843).
It's a combination of different automatic features that normally we don't have to think about, but in this case don't work well. We can fix this by following the advice in the error message for 843 and calling the default constructor as part of your explicit constructor:
public DealImportRequest(DealRequestBase drb)
:this()
{
DealReq = drb;
ImportRetryCounter = 0;
}
Considering this in relation to my expanded version of your code above, you can see how this solves the problem, because it calls the constructor that assigns to the backing fields before it proceeds.
I would recommend not using auto-properties with structures unless you have a good reason to use them. Wrapping a class field in a read-write property is useful because it makes it possible for an instance to control the circumstances where it may be read or written, and take action when a read or write takes place. Further, code within an object instance can identify the instance being acted upon, and may thus perform a special action only when reading and writing a particular instance. Using an auto-property in an early version of a class will make it possible for future versions of the class to use a manually-implemented property including the aforementioned benefits while retaining compatibility with already-compiled client code. Unfortunately, wrapping a struct field in a read-write property doesn't offer those same benefits because the fields of one struct instance can be copied to another without either instance having any say in the matter. If the semantics of a struct allow a property to be written with arbitrary values in most instances [as would be the case for an auto-property], then any legitimate replacement would be semantically equivalent to a field.
In the Framework we are building we need the following pattern:
public class BaseRenderer
{
Func<string> renderer;
public BaseRenderer(Func<string> renderer)
{
this.renderer = renderer;
}
public string Render()
{
return renderer();
}
}
public class NameRenderer : BaseRenderer
{
public string Name{ get; set; }
public NameRenderer ()
: base(() =>this.Name)
{}
}
As you see, we create a lambda when calling the base constructor.
public class Program
{
public static void Main()
{
Console.WriteLine(new NameRenderer(){Name = "Foo"}.Render());
}
}
Oddly, when trying to actually use the lambda it throws NullReferenceException (Console Application), or some kind of ExecutionEngineExceptionexception (Web app on IIS).
I think the reason is that this pointer is not ready before calling base constructor, so the lambda is unable to capture this.Name at this stage.
Shouldn't it throw an exception in "capture time" instead of "execution time"?
Is this behavior documented?
I can refactor the code in a different way, but I think it worths a comment.
As asgerhallas correctly points out, this should not be legal according to the specification. We accidentally allowed this bogus usage to sneak by the error detector that searches for incorrect usages of "this" before it is legal to do so. I've fixed the bug; the C# 4 compiler correctly flags your program as an error.
Many apologies for the inconvenience; this was my mistake.
The C# specification at 7.5.7 says: "A this-access is permitted only in the block of an instance constructor, an instance method, or an instance accessor."
And even more directly in 10.11.1: "An instance constructor initializer cannot access the instance being created. Therefore it is a compile-time error to reference this in an argument expression of the constructor initializer, as is it a compile-time error for an argument expression to reference any instance member through a simple-name."
Though the instance has been created according to 7.5.10.
Hmm. That's actually pretty strange. I did not see any compile-time error.
I think you are right. The subclass is not yet constructed when the base class constructor is called and therefore accessing members on the subclass gives you a null reference. CLR doesn't have a way to know at compile time if the instance exists or not.
Moving the logic to the constructor body should fix the problem.
The lambda captured the value of "this" and captured null since the object wasn't constructed yet. This strikes me as a compiler bug, it should have generated an error for this. Code like this normally generates a CS0027 (keyword 'this' is not available in the current context) or CS0120 (an object reference is required). I bet that isn't easy to implement.
Anyhoo, the code cannot work. The NameRenderer class needs a constructor with a string argument so it can initialize the base class.
wouldn't : base(()=>this) be legal? You can do : this() so a reference to this seems to be fine, just not properties on it. The fact that : base(()=>this) is no longer legal just broke some partial function application I did during construction. Can be fixed by moving it into the body of the constructor, but there is an order difference: the base class can no longer be passed transparently a partial function application to itself (because the base class constructor gets called before the body of the subclass constructor).