I'm trying to write some code that sets a property on a struct (important that it's a property on a struct) and it's failing:
System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle();
PropertyInfo propertyInfo = typeof(System.Drawing.Rectangle).GetProperty("Height");
propertyInfo.SetValue(rectangle, 5, null);
The Height value (as reported by the debugger) never gets set to anything - it stays at the default value of 0.
I have done plenty of reflection on classes before and this has worked fine. Also, I know that when dealing with structs, you need to use FieldInfo.SetValueDirect if setting a field, but I don't know of an equivalent for PropertyInfo.
The value of rectangle is being boxed - but then you're losing the boxed value, which is what's being modified. Try this:
Rectangle rectangle = new Rectangle();
PropertyInfo propertyInfo = typeof(Rectangle).GetProperty("Height");
object boxed = rectangle;
propertyInfo.SetValue(boxed, 5, null);
rectangle = (Rectangle) boxed;
Ever heard of SetValueDirect? There's a reason they made it. :)
struct MyStruct { public int Field; }
static class Program
{
static void Main()
{
var s = new MyStruct();
s.GetType().GetField("Field").SetValueDirect(__makeref(s), 5);
System.Console.WriteLine(s.Field); //Prints 5
}
}
There's other methods than the undocumented __makeref which you could use (see System.TypedReference) but they're more painful.
Related
I'm trying to write some code that sets a property on a struct (important that it's a property on a struct) and it's failing:
System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle();
PropertyInfo propertyInfo = typeof(System.Drawing.Rectangle).GetProperty("Height");
propertyInfo.SetValue(rectangle, 5, null);
The Height value (as reported by the debugger) never gets set to anything - it stays at the default value of 0.
I have done plenty of reflection on classes before and this has worked fine. Also, I know that when dealing with structs, you need to use FieldInfo.SetValueDirect if setting a field, but I don't know of an equivalent for PropertyInfo.
The value of rectangle is being boxed - but then you're losing the boxed value, which is what's being modified. Try this:
Rectangle rectangle = new Rectangle();
PropertyInfo propertyInfo = typeof(Rectangle).GetProperty("Height");
object boxed = rectangle;
propertyInfo.SetValue(boxed, 5, null);
rectangle = (Rectangle) boxed;
Ever heard of SetValueDirect? There's a reason they made it. :)
struct MyStruct { public int Field; }
static class Program
{
static void Main()
{
var s = new MyStruct();
s.GetType().GetField("Field").SetValueDirect(__makeref(s), 5);
System.Console.WriteLine(s.Field); //Prints 5
}
}
There's other methods than the undocumented __makeref which you could use (see System.TypedReference) but they're more painful.
I am working with GDI+ and need to create a Brush or Pen. In most cases I should use a "color Struct". Searching around I see two different styles: One is like this:
Brush B1 = new SolidBrush(Color.FromArgb(255, 0, 0));
and the other is:
Color myColor;
myColor = Color.FromArgb(255,0,0);
Brush B2 = new SolidBrush(myColor);
Can anyone describe how can we use a Color without declaring an instance of the Struct with new operator that calls the default constructor.
All that is going on here is that the interesting constructor is non-public, and you must create the value via a static utility method. You can achieve the same thing trivially in your own code:
struct Indirect
{
private readonly int value;
private Indirect(int value)
{
this.value = value;
}
public static Indirect Create(int value)
{
return new Indirect(value);
}
}
struct Direct
{
private readonly int value;
public Direct(int value)
{
this.value = value;
}
}
class Program
{
static void Main()
{
var x = Indirect.Create(42);
var y = new Direct(42);
}
}
Sometimes the expected usage is that the caller uses new; sometimes the expected usage is that the caller gets handed values from a helper method. In the case of Color: the latter. In the case of SolidBrush: the former. Note that this can be the case for both struct and class types - that is not the distinguishing factor.
In the case of Color, there are actually many more fields than you see directly; for example, knownColor, name, state - separately to the ARGB values. Some colors are "known" (from pre-defined named lists); some colors are ad-hoc (from ARGB data). The way you get the color determines these additional values.
The constructors of the type System.Drawing.Color are private and internal, meaning you can't call them from your code.
You'll need to instantiate a color through the given static methods and properties it contains, like Color.FromArgb() or Color.White.
As for the comments, which now make the question clear: those methods and properties are static, which means you don't call them on an instance (new Color().White) but on the type (Color.White).
Judging from its behavior, the method
Color.FromArgb(int red, int green, int blue)
most probably calls
new Color()
in its implementation, i.e. it declares an instance of the struct Color with the new operator.
Both implementations are equal, however
Brush B1 = new SolidBrush(Color.FromArgb(255, 0, 0));
is shorter. I'd rather use even shorter in the case
Brush B1 = new SolidBrush(Color.Red); // R = 255, G = 0, B = 0 is just "Red"
Note, that Brush is IDisposable, that's why it seems that you have put it
using (Brush B1 = new SolidBrush(Color.Red)) {
... // Working with brush
}
How do you easily clone (copy) a RectangleF in C#?
There are obviously inelegant ways to do it, such as new RectangleF(r.Location, r.size), but surely there's a .Copy or .Clone method hiding somewhere? But neither of those compiles for me, nor does there appear to be a copy constructor. I suspect there's some simple, C#-standard way of copying any struct, that I just haven't found yet.
In case it matters, my real objective is to make a method that returns an offset version of a rectangle (because, amazingly, RectangleF doesn't have such built in - it has only a mutator method). My best stab at this is:
public static RectangleF Offset(RectangleF r, PointF offset) {
PointF oldLoc = r.Location;
return new RectangleF(new PointF(oldLoc.X+offset.X, oldLoc.Y+offset.Y), r.Size);
}
(Made uglier than it should by be the astounding lack of an addition operator for PointF, but that's another issue.) Is there a simpler way to do this?
RectangleF is a struct i.e. a value type. Consider the following:
public class Program
{
struct S
{
public int i;
}
static void Main(string[] args)
{
S s1 = new S();
S s2 = s1;
s1.i = 5;
Console.WriteLine(s1.i);
Console.WriteLine(s2.i);
}
}
The output is:
5
0
Because S is a struct i.e. s2 is a copy of s1.
A Rect is a struct, a value type.
To clone it just assign it to a new variable.
I'm not sure of the terminology for this kind of code, but I want to know if it's possible to instantiate variables after the parentheses, but whilst using reflection.
I have a map which gets loaded from an XML file. This is a collection of (int X, int Y, string S) where the X,Y is the position of some terrain, and S is a string representing the type of the terrain. I have a dictionary to pass between the strings and the relevant types; for example one key-value pair might be "Tree", typeof(Tree).
When using reflection, although I know it's possible to instantiate with parameters, the only way I'm comfortable is just by using Activator.CreateInstance(Type t), i.e. with an empty constructor.
When I had the maps hard coded, I would originally instantiate like this (within some i,j for loop):
case: "Tree"
world.Add( new Tree(i,j) );
Whilst starting to think about reflection and my save file, I changed this to:
world.Add( new Tree() { X = i, Y = j }
However, I realised that this won't work with reflection, so I am having to do the following (Tree inherits from Terrain, and the dictionary just converts the XML save data string to a type):
Type type = dictionary[dataItem.typeAsString];
Terrain t = (Terrain)Activator.CreateInstance(type);
t.X = i;
t.Y = j;
world.Add(t);
I would prefer to do this using something like
Type type = dictionary[dataItem.typeAsString];
world.Add((Terrain)Activator.CreateInstance(type) { X = i, Y = j }
Is there any shortcut like this? I guess if not I could edit world.Add to take an X and Y and cast to Terrain in there to access those variables, but I am still curious as to a) what this {var1 = X, var2 = Y} programming is called, and b) whether something similar exists when using reflection.
This syntax is called Object Initializer syntax and is just syntactic sugar for setting the properties.
The code var result = new MyType { X = x } will be compiled to this:
MyType __tmp = new MyType();
__tmp.X = x;
MyType result = __tmp;
You will have to do that yourself using PropertyInfo.SetValue if you know the instantiated type only at runtime or use the normal property setters if the type is known at compile time.
The answer is no, because the object initialization syntax you mention (introduced with LINQ in 3.0) is an illusion of the compiler. As in, when you type this
var foo = new Foo { Bar = "baz" };
the compiler actually converts it into CLS-compliant IL which equates to
var foo = new Foo();
foo.Bar = "baz";
Phil Haack has a great blog post which not only covers the details of this rewriting done by the compiler, but also some side effects it can cause when dealing with types that implement IDisposable
As all of this is nothing but a feint by the compiler, there is no equivalent using reflection (i.e., Activator.CreateInstance(Type t)). Others will give you workarounds, but in the end there really is no direct equivalent.
Probably the closest generic hack you could manage would be to create a method that accepted an object, then used reflection in order to identify the properties of that object and their respective values in order to perform object initialization for you. It might be used something like this
var foo = Supercollider.Initialize<Foo>(new { Bar = "baz" });
and the code would be something like (this is off the top of my head)
public sealed class Supercollider
{
public static T Initialize<T>(object propertySource)
{
// you can provide overloads for types that don't have a default ctor
var result = Activator.CreateInstance(typeof(T));
foreach(var prop in ReflectionHelper.GetProperties(typeof(T)))
ReflectionHelper.SetPropertyValue(
result, // the target
prop, // the PropertyInfo
propertySource); // where we get the value
}
}
You'd have to get each property from the anonymous object, find a property in your target type with the same exact name and type, then get the value from that property in the anonymous object and set the value of your target's property to this value. Its not incredibly hard, but its absolutely prone to runtime exceptions and issues where the compiler chooses a different type for the anonymous type's property, requiring you be more specific (e.g., new { Bar = (string)null }), which screws with the elegance of the thing.
(T)Activator.CreateInstance(typeof(T), param1, param2, ...);
As described HERE.
public sealed class ReflectionUtils
{
public static T ObjectInitializer<T>(Action<T> initialize)
{
var result = Activator.CreateInstance<T>();
initialize(result);
return result;
}
}
public class MyModel
{
public string Name{get;set;}
}
And after that just make the call :
var myModel = ReflectionUtils.ObjectInitializer<MyModel>(m =>
{
m.Name = "Asdf"
});
The advantage is that in this way you will have type safety and use reflection as minimum required, because we all know that reflection is an expensive operation that should be avoided as much as possible.
You could create a constructor which takes those arguments, then use
Activator.CreateInstance(type, i, j)
But you won't be able to use the object initialization syntax. Which is just sugar candy for setting the properties.
I am trying to write the following code:
public const Size ImageSize = new Size() { Width = 28, Height = 28 };
But I get the error that Width and Height are read-only.
What is the recommended way to do this?
const is restricted to primitives that the compiler can directly write as IL directly. readonly should suffice here if Size is treated as immutable, i.e.
public static readonly Size ImageSize = new Size(28,28);
Note that if Size is a mutable struct, bad things can happen; I would recommend a property rather than a field to prevent a number of confusing side-effects.
The fundamental problem is that you cannot declare an object of type System.Drawing.Size as const. That indicates that the symbol is to be replaced at compile-time with the value of the constant.
Instead, you should use readonly. This is also a "constant" value in the sense that it cannot be modified once the constructor has run, but the objects are created at run-time instead of compile-time.
The following code compiles just fine:
public static readonly Size ImageSize = new Size() { Width = 28, Height = 28 };
public static readonly Size ImageSize = new Size(28,28);
You have to do this instead:
public readonly Size ImageSize = new Size(28, 28);
Making the instance read only to prevent it to be changed, as you cannot create Size as a constant.
From the docs:
A constant expression is an expression that can be fully evaluated at compile time. Therefore, the only possible values for constants of reference types are string and null.
The code you're writing:
public const Size ImageSize = new Size() { Width = 28, Height = 28 };
Actually compiles down to the same as this:
public const Size ImageSize = new Size();
ImageSize.Width = 28;
ImageSize.Height = 28;
The version your using, called the object initializer, is just syntactic shorthand for the latter version above. The two are logically identical. In the latter version you can see why it's giving you the error, you can't set properties on a const after it's been declared.
More to the point, I'm not sure if you can even use a reference type like that as a const. I'm not sure about that, as I can't say I ever tried it. You may try readonly instead. Though you may run into the same or similar issue.
Does Size have a constructor you can call with the parameters, rather than using the object initializer?
You can use :
public static readonly Size ImageSize = new Size(28, 28);
It's not actually a const, but it won't be changed after the initialization.
You need to use a constructor that takes width and height as parameters.
Also, the expression must be completely evaluable during compile time. That might not work with your Size type (don't know which one it is). If so (like with System.Drawing.Size), you might consider using readonly instead of const.