I want to do some comparing of member properties at runtime but value type prohibits unusual behaviour.
I have something like the following
public static object DefaultValue(this Type type)
{
return type.IsValueType ? Activator.CreateInstance(type) : null;
}
class ExampleClass
{
public string Id { get; set; }
public string Title { get; set; }
public decimal Price { get; set; }
public XElement ToXml()
{
var srcTree = from prop in GetType().GetProperties()
let value = prop.GetValue(foo, null)
where value != prop.PropertyType.DefaultValue()
select new XElement(prop.Name.ToLower(), value);
...
}
}
if I initialize my object new ExampleClass() I find the price with a value of 0. I can confirm DefaultValue() returns 0 for the price which is not equal to 0 during equality comparison. Is because now it’s comparing objects or what. What can I achieve the behaviour I want?
object DefaultValue(this Type type)
the method returns an object, Although you judge whether it is a value type in the method and use Activator.CreateInstance create the type dynamically.
but the value will be boxing in an object be an object type value instead of your expected value type.
When you used == on an expression of type object, it'll use ReferenceEquals to compare the references instead of value.
var srcTree = from prop in GetType().GetProperties()
let value = prop.GetValue(foo, null)
where !Equals(value, prop.PropertyType.DefaultValue())
select new XElement(prop.Name.ToLower(), value);
c# online
Here is a sample for your case
we can saw defaultVal object set a value 0, which is int type (doing boxing).
dymanicVal created int by Activator.CreateInstance method.
Then when we use == to compare two objects they will compare their reference instead of int value
so you can try to use Equals method to compare the value will call RuntimeHelpers.Equals method then compare their value instead of references.
object defaultVal = 0;
object dymanicVal = Activator.CreateInstance(typeof(int));
Console.WriteLine(Equals(defaultVal, dymanicVal)); //True
Console.WriteLine(defaultVal == dymanicVal); //false
c# online
Related
So, i have trouble casting System.Nullables like from int?.
After some research i modifed my code but i dont have any idea how get the type by just Name out of my Class.
for (int i = 0; i < m_textEdits.Count; i++)
{
string fieldName = m_textEdits[i].Name.Substring(m_textEdits[i].Name.LastIndexOf("_") + 1);
System.Reflection.PropertyInfo propInfo = m_aktuelleZeille.GetType().GetProperty(fieldName);
if (propInfo != null)
{
if (propInfo.GetMethod.ToString().Contains("Null"))
{
propInfo.SetValue(m_aktuelleZeille, m_textEdits[i].EditValue ?? default( IDK WHAT TO PUT IN HERE ));
}
else if (propInfo.SetMethod != null) propInfo.SetValue(m_aktuelleZeille, m_textEdits[i].EditValue);
}
}
m_texedits is List of Textedits, a Textedit is called for example "tb_Menge" so in fieldname stands "Menge" and m_aktuelleZeille is my Class which contains as example:
private int? menge;
public int? Menge
{
get { return menge; }
set
{
if (value != menge)
{
menge = value;
OnPropertyChanged("Menge");
}
}
}
The else if is working fine, just if i get nullable Types (that why i implented the if)
I'm unsure exactly what you're asking but I think you're looking to get the default value of the underlying type. e.g. if int? then default for int, which is 0?
If that's the case then you can use GenericTypeArguments on the PropertyInfo object which will give you the generic arguments for the Nullable<T>, you can then use that to get the default value.
E.g.
var defaultValue = Activator.CreateInstance(propInfo.GenericTypeArguments.First());
However, I would use caution as the default value for Nullable<T> is null, not whatever the default of the underlying value is. See What is the default value of the nullable type "int?" (including question mark)? for more on this.
I'm using reflection to retrieve the value of a property from an object. The value is an enum:
enum MyEnum
{
None,
SomeValue
}
Which is on an object, and the property also has an attribute
class MyObject
{
[MyAttribute(ExclusionValue = MyEnum.None)]
public MyEnum EnumProperty { get; set; }
}
So when I get to the reflection part of things I would like to check if the value is equal to the ExclusionValue
// exclusionValue is the value taken from the attribute
// propertyValue is the value retrieved by reflection of the containing object, so at
// this time it just an `object` type.
if(exclusionValue == propertyValue)
{
// Both values are `MyEnum.None` but the if statement never evaluates true.
}
I've tried to cast the exclusionValue to an object so that they are both the same visible type
if((object)exclusionValue == propertyValue)
But this never returns true either. They are definitely the same enum value. Also, I can't explicitly cast anything in this if statement because there are many other properties in the object of all different types (not just enums) that need this same check, for example:
class MyObject
{
[MyAttribute(ExclusionValue = MyEnum.None)]
public MyEnum EnumProperty { get; set; }
[MyAttribute(ExclusionValue = false)]
public bool BoolProperty { get; set; }
}
Edit
They will only ever be value types (no structs) or strings.
You need to unbox the object you got via reflection to a MyEnum.
Currently you are comparing objects for equality, which tests for reference equality. They are not the same object, so it returns false.
This should behave as you expect:
if (exclusionValue == (MyEnum)propertyValue)
Or, you can call the Equals method instead:
if (exclusionValue.Equals(propertyValue))
Which will call the Enum.Equals method, which will do the right thing.
I'm having this issue, I'm using reflection to pull properties from a class but the problem is reflection returns them as an object and I can't get it into my actual type.
Take for example, if this is the class:
public class Row<T>
{
public static explicit operator Row<object>(Row<T> o)
{
return new Row<object>
{
Name = o.Name,
Value = o.Value
};
}
public string Name { get; set; }
public T Value { get; set; }
}
Casting from one say Row<bool> to Row<object> works:
var a = new Row<bool>
{
Name = "Foo",
Value = true
};
var b = (Row<object>)a; // Works
But when I try to go from object to Row<object> it seems to ignore my explicit operator and throw a System.InvalidCastException:
var c = (object) a; // Simulate getting from reflection
var d = (Row<object>) c; // System.InvalidCastException
What am I missing?
Use dynamic instead of object to force runtime real type check:
var c = (dynamic)a;
var d = (Row<object>)c; // Works fine
It will call your Row<T> -> Row<object> cast operator.
The problem here is that casting does not look for a conversion operator unless one is defined on the static type of the value you are trying to cast. In your example the static type of c is object and object neither derives from nor has a conversion operator to Row<object>, resulting in the runtime exception.
It looks like this problem can be easily sidestepped with a better design.
You want to treat any type of Row<T> as a Row<object> and the conversion operator does nothing more than work around the fact that these types are not hierarchically related. So why not make them related and avoid the problem in the first place?
For example:
public abstract class Row
{
public string Name { get; set; }
public object Value { get; protected set; }
}
public class Row<T> : Row
{
public new T Value
{
get { return (T)base.Value; }
set { base.Value = value; }
}
}
This seems to do what you want:
The casting problem is solved because you can now cast any type of Row<T> to the base class Row (which takes over the responsibilities of Row<object> in your initial design) and easily access Name and Value no matter what type the Value is.
The Row.Value setter is protected so you cannot cast a Row<int> to Row and make Value e.g. a string from outside, maintaining type safety.
You can accomplish this with reflection:
public class RowHelper
{
public static Row<object> LoadRow(object o)
{
var type = o.GetType();
return new Row<object>
{
Name = (string)type.InvokeMember("Name", BindingFlags.GetProperty, null, o, null),
Value = type.InvokeMember("Value", BindingFlags.GetProperty, null, o, null)
};
}
}
You would call this with:
var d = RowHelper.LoadRow(c);
I have got an c# object and I don't know the type of this object. (i.e. object o)
What I know is that this object has a member called 'ID' of type int.
I wanted to get the value of this property but I am not good enough with reflection...
I can get a type and members of this object:
Type type = obj.GetType();
System.Reflection.MemberInfo[] member = type.GetMember("ID");
...but don't know what to do next :-)
Thanks for help in advance
Mariusz
Is this a public property? Is so then the easiest route is to use dynamic
int value = ((dynamic)obj).ID;
You can use:
Type type = obj.GetType();
PropertyInfo property = type.GetProperty("ID");
int id = (int) property.GetValue(obj, null);
Use PropertyInfo because you know it's a property, which makes things easier
Call GetValue to get the value, passing in obj as the target of the property and null for indexer arguments (as it's a property, not an index)
Cast the result to int as you already know it's going to be an int
Jared's suggestion of using dynamic is good too, if you're using C# 4 and .NET 4, although to avoid all the brackets I'd probably write it as:
dynamic d = obj;
int id = d.ID;
(unless you needed it in a single expression for some reason).
Can you use C# 4 ? In that case, you can use dynamic:
dynamic dyn = obj;
int id = dyn.ID;
public class TestClass
{
public TestClass()
{
// defaults
this.IdField = 1;
this.IdProperty = 2;
}
public int IdField;
public int IdProperty { get; set; }
}
// here is an object obj and you don't know which its underlying type
object obj = new TestClass();
var idProperty = obj.GetType().GetProperty("IdProperty");
if (idProperty != null)
{
// retrieve it and then parse to int using int.TryParse()
var intValue = idProperty.GetValue(obj, null);
}
var idField = obj.GetType().GetField("IdField");
if (idField != null)
{
// retrieve it and then parse to int using int.TryParse()
var intValue = idField.GetValue(obj);
}
Googling is only coming up with the keyword, but I stumbled across some code that says
MyVariable = default(MyObject);
and I am wondering what it means.
For a reference-type, it returns null
For a value-type other than Nullable<T> it returns a zero-initialized value
For Nullable<T> it returns the empty (pseudo-null) value (actually, this is a re-statement of the second bullet, but it is worth making it explicit)
The biggest use of default(T) is in generics, and things like the Try... pattern:
bool TryGetValue(out T value) {
if(NoDataIsAvailable) {
value = default(T); // because I have to set it to *something*
return false;
}
value = GetData();
return true;
}
As it happens, I also use it in some code-generation, where it is a pain to initialize fields / variables - but if you know the type:
bool someField = default(bool);
int someOtherField = default(int);
global::My.Namespace.SomeType another = default(global::My.Namespace.SomeType);
default keyword will return null for reference types and zero for numeric value types.
For structs, it will return each member of the struct initialized to zero or null depending on whether they are value or reference types.
from MSDN
Simple Sample code :<br>
class Foo
{
public string Bar { get; set; }
}
struct Bar
{
public int FooBar { get; set; }
public Foo BarFoo { get; set; }
}
public class AddPrinterConnection
{
public static void Main()
{
int n = default(int);
Foo f = default(Foo);
Bar b = default(Bar);
Console.WriteLine(n);
if (f == null) Console.WriteLine("f is null");
Console.WriteLine("b.FooBar = {0}",b.FooBar);
if (b.BarFoo == null) Console.WriteLine("b.BarFoo is null");
}
}
OUTPUT:
0
f is null
b.FooBar = 0
b.BarFoo is null
Specifies the default value of the
type parameter.This will be null for
reference types and zero for value
types.
See default
Default value of MyObject. See default Keyword in Generic Code (C# Programming Guide) (MSDN):
In generic classes and methods, one issue that arises is how to assign
a default value to a parameterized type T when you do not know the
following in advance:
Whether T will be a reference type or a value type.
If T is a value type, whether it will be a numeric value or a struct.
Given a variable t of a parameterized type T, the statement t = null
is only valid if T is a reference type and t = 0 will only work for
numeric value types but not for structs. The solution is to use the
default keyword, which will return null for reference types and zero
for numeric value types. For structs, it will return each member of
the struct initialized to zero or null depending on whether they are
value or reference types. The following example from the
GenericList class shows how to use the default keyword. For more
information, see Generics Overview.
public class GenericList<T>
{
private class Node
{
//...
public Node Next;
public T Data;
}
private Node head;
//...
public T GetNext()
{
T temp = default(T);
Node current = head;
if (current != null)
{
temp = current.Data;
current = current.Next;
}
return temp;
}
}
The default keyword returns the "default" or "empty" value for a variable of the requested type.
For all reference types (defined with class, delegate, etc), this is null. For value types (defined with struct, enum, etc) it's an all-zeroes value (for example, int 0, DateTime 0001-01-01 00:00:00, etc).
It's mostly used with generic code that can be applied to both reference and value types, because you can't assign null to a value type variable.
It will set the default value of an object to a variable:
null for reference types and 0 for value types.
Perhaps this may help you:
using System;
using System.Collections.Generic;
namespace Wrox.ProCSharp.Generics
{
public class DocumentManager < T >
{
private readonly Queue < T > documentQueue = new Queue < T > ();
public void AddDocument(T doc)
{
lock (this)
{
documentQueue.Enqueue(doc);
}
}
public bool IsDocumentAvailable
{
get { return documentQueue.Count > 0; }
}
}
}
It is not possible to assign null to generic types. The reason is that a generic type can also be instantiated as a value type, and null is allowed only with reference types. To circumvent this problem, you can use the default keyword. With the default keyword, null is assigned to reference types and 0 is assigned to value types.
public T GetDocument()
{
T doc = default(T);
lock (this)
{
doc = documentQueue.Dequeue();
}
return doc;
}
The default keyword has multiple meanings depending on the context where it is used. The switch
statement uses a default for defining the default case, and with generics the default is used to initialize generic types either to null or 0 depending on if it is a reference or value type.
When constraints have not been applied to restrict a generic type parameter to be a reference type, then a value type, such as a struct, could also be passed. In such cases, comparing the type parameter to null would always be false, because a struct can be empty, but never null
wrong code
public void TestChanges<T>(T inputValue)
try
{
if (inputValue==null)
return;
//operation on inputValue
}
catch
{
// ignore this.
}
}
corrected
public void TestChanges<T>(T inputValue)
try
{
if (object.Equals(inputValue, default(T)) )
return;
//operation on inputValue
}
catch
{
// ignore this.
}
}
Another good use of default(T) is when compiler can't determine returning type, like in here
class X
{
public int? P {get; set;}
}
// assigning in code
var x = new X();
// consider coll["key"] returns object boxed value
// data readers is one such case
x.P = myReader["someColumn"] == DbNull.Value ? default(int?) : (int)myReader["someColumn"];