PropertyInfo.GetValue(null) - how it should behave? - c#

I'm writing a compare properties two objects of some class, for further listing differences.
Class oldObj, newObj;
//some initiation of above
Class classObject = new Class();
var objectKeys = classObject .GetType().GetProperties().ToList();
objectKeys.ForEach(key => {
var previousKeyValue = key.GetValue(oldObj);
var newKeyValue = key.GetValue(newObj);
if (!Equals) {...}
});
In special cases, newObj or oldObj can be nulls.
My problem is that, in such a case: key.GetValue(null) I'm getting CS0120 exception - "Non-static method requires a target".
Looking at PropertyInfo options (from metadata):
public object? GetValue(object? obj);
I assumed that it will be able to handle such a situation with object being null, with e.g. return null as its value.
Could you please explain if this is proper behaviour of this code, or I'm making something wrong to use null?
In such a case I would probably just before ForEach make some verification if objects are nulls and write separate compare code, handling this situation.

You are misunderstanding the nature of the parameter that is passed to GetValue().
When you pass in an object reference, it means that the reference is an instance property on an instance of an object. If you omit the object reference, you are telling the reflection api that you are trying to access a static member.

Related

C# Object - get properties from json within the object

My HTTP response data includes a field that is structured as a Dictionary<string,object>. Accessing the Object in debug mode shows me what I expect to see, i.e.
ValueKind = Object:
{ "someProp" : "someValue",
"anotherProp" : "anotherValue" .. }
=> the object therefore contains the large json formatted data that I need to access. However, I can't figure out how to do that .. The commonly suggested method returns null:
var myValue = Odata.GetType().GetProperty("someProp").GetValue(Odata, null);
which makes me think there is something I should be serializing which I am not and regardless how much I tried, I can't find any methods to work.
Here is some more info, if it is not enough I will add whatever is needed. I broke it down a lot to try to show clearly what I am getting each step):
// assume Odata = the Object value from the dictionary
//perform reflection
var type = Odata.GetType() // this gives System.Text.json.JsonElement
//get type properties at runtime
var props = type.GetProperties()
//returns array of 2 :
//System.Text.Json.ValueKind and System.Text.json.JsonElement
//attempting to access my properties in the JsonElement
var someValue= type.GetProperty("someProp").GetValue(Odata,null) //this gives null
I don't necessarily want an exact solution, but pointing me to the right place to read would also be very useful!
When you do GetType().GetProperty() you're using the GetProperty() method from Type class, you're using reflection. You want to use the GetProperty method of JsonElement class instead:
var myValue = Odata.GetProperty("someProp").GetString();

C# access to stack object property

How can I access the objects property in this situation?
Araba araba = new Araba();
araba.Renk = "mavi";
araba.fiyat = 12345;
// I created this class and it working normally
ArrayTypedStack asd = new ArrayTypedStack(10);
asd.Push(araba);
object araba2 = asd.Pop();
araba2. //cant access
Here you are assigning the value of asd.Pop() to a variable of the type object.
object is the root of all objects (all objects inherit from it and can be casted to it) and as such has no real information about what it is. It's just like any object in real life is a thing.
The solution here is to declare the araba2 as the type Araba, that will give you access to all the properties on the next line.
I don't know the implementation of the ArrayTypedStack and what the Pop() method looks like (it's return type) so it's possible that this will give you an error, saying that it can't convert an object to the type Araba. This is the type safety implemented in .NET. You have to convince .NET that it's of the type Araba, this can be by casting
Araba araba2 = (Araba)asd.Pop();
this can still give an error on runtime if the object returned from Pop() isn't of the type Araba, in this case you can ask .NET to try to cast it, there are serveral options for this:
object popResult = asd.Pop();
if (popResult is Araba) {
Araba araba2 = (Araba)popResult;
}
// can be written as follows:
if (popResult is Araba araba3) {
araba3.fiyat = 65432;
}
// can also be done as follows
Araba araba4 = asd.Pop() as Araba;
if (araba4 != null) {
araba4.fiyat = 84368;
}
Well, your araba2 variable is of type object. Thus, regardless of the actual type of the instance it contains, through the object variable araba2 you can only access members that are provided by the type object.
To access members provided by the Araba type (and assuming the instance in the araba2 variable is an instance of type Araba), the araba2 variable itself should be of type Araba, or the value of araba2 needs to be cast as Araba.
Thus,
var araba2 = asd.Pop();
or
var araba2 = (Araba) asd.Pop();
with the first example code line above requiring that the return type of the Pop method is Araba (or a type derived from Araba). The latter code line example will work regardless of the return type of Pop as long as the value returned by Pop is an actual Araba instance (or is something that is convertible to an Araba instance).

Is it possible to create an anonymous generic object?

Imagine that you want to declare an object with an anonymous type, but you need it to be generic (I can't think of an actual reason why, this is theoretical). How would you create such an object?
For example:
var anonymousGeneric = new <T>{ }; // <- doesn't work
var anonymousGeneric = Activator.CreateInstance((new { }).GetType()); // Not generic
edit:
// because:
(new { }).GetType().IsGenericType == false
// Of course, any useful anonymous object _will_ be generic:
(new { a="b" }).GetType().IsGenericType == true
// But in the process of testing various aspects of this question
// it had never occurred to me that I needed to supply any property
// (this was all theoretical, remember)
end edit
But neither of those works. Of course, the real-world solution to this imagined problem is to define an actual class definition:
public GenericThing<T> { }
But that isn't anonymous like above.
Once the object is created, imagine using it later on with something like:
var anonymousGenericType = anonymousGeneric.GetType();
// These throw exception
// <>f__AnonymousType0#1 is not a GenericTypeDefinition. MakeGenericType may only be called on a type for which Type.IsGenericTypeDefinition is true.
// + System.RuntimeType.MakeGenericType(System.Type[])
var intThing = anonymousGenericType.MakeGenericType(typeof(int));
var stringThing = anonymousGenericType.MakeGenericType(typeof(string));
In summary, is it possible to create an anonymous generic object?
(I can't think of an actual reason why, this is theoretical)
In that case, let's stick with the simple and obvious, since it's easier to find a reason: simply create a regular anonymous object from a generic method.
public object Foo<T>(T t) { return new { t }; }
Here, Foo(0) and Foo("") will necessarily return different types, but they'll still share a type definition.
Pretty much any use of anonymous types can make equal sense inside a generic method.
anonymousGeneric.GetType() is returning the wrong type of generic type: Closed (with type parameter(s)) vs open (without)1. If you want to change a type parameter, you need to get the generic type definition from it.
The following actually works, though I can't imagine what good it does anybody 2:
var anonymousGeneric = new {a = "b"};
var anonymousGenericType = anonymousGeneric.GetType().GetGenericTypeDefinition();
var intThingType = anonymousGenericType.MakeGenericType(typeof(int));
var intThingInstance = Activator.CreateInstance(intThingType, 9);
Now we have a thing just like anonymousGeneric, but its type parameter is int instead of string, and its a property is 9. But what's it good for? How do you declare a reference to it? You could bind to its properties in XAML, if you had some time on your hands.
1 Thanks to Amy and Servy for pitching in to clear up my confusion with terminology.
2 Note that there are more things in heaven and earth than are dreamt of in my philosophy.

How to display the return value from a non static method in C#

I am working with a non static class and want to display the answer of the method to the console window.
When I change the method to static and call from Main() an error stating "Object reference not set to an instance of an object" appears.
http://msdn.microsoft.com/query/dev12.query?appId=Dev12IDEF1&l=EN-US&k=k(EHNullReference);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5);k(DevLang-csharp)&rd=true
Why can't you call a non-static method from a static method?
According to this article I need to create an instance of the object using the "new" keyword. My understanding is that you have to create an object for a class and not a method.
http://msdn.microsoft.com/en-us/library/ms173110.aspx
So, I created a new object but it does not return the result.
GetSingleAsset Foo = new GetSingleAsset();
Console.WriteLine(Foo);
The output just gives the name of the method.
How can I see the return value of this non static method?
public Asset GetSingleAsset()
{
var memberId = Oid.FromToken("Member:20", _context.MetaModel);
var query = new Query(memberId);
var nameAttribute = _context.MetaModel.GetAttributeDefinition("Member.Name");
var emailAttribute = _context.MetaModel.GetAttributeDefinition("Member.Email");
query.Selection.Add(nameAttribute);
query.Selection.Add(emailAttribute);
var result = _context.Services.Retrieve(query);
var member = result.Assets[0];
LogResult(member.Oid.Token,
GetValue(member.GetAttribute(nameAttribute).Value),
GetValue(member.GetAttribute(emailAttribute).Value));
return member;
}
You need to do this:
NameOfYourClass instanceOfClass = new NameOfYourClass();
Console.WriteLine(instanceOfClass.NameOfMethod());
The "answer of the method to the console window" - in this case, is an object - and if you attempt to Console.WriteLine() an object, you will only see the object type written out to the Console - not its values.
Yes, Robert is correct - GetSingleAsset() is a method, not a class - because it returns a value of 'Asset' type - a class's constructor will have no return - and Patrick is correct if you want to see (via Console output) what the return is from that particular method - if it wasn't an object.
However, since 'Asset' is an object itself, if you simply did a Console.WriteLine(Asset) it would show you what the type of Asset deviates from .. not its values. For example, "System.Collection.Asset" would be printed and not the values that you are interested in.
You will need to put a breakpoint in the code at the point of class instantiation and look through the Locals Window to see the values that type 'Asset' contains and print out exactly the values that you are interested in ... chances are what values you are actually interested in are contained within another object within the Asset class .. perhaps a for loop is in order here.

Property / field initializers in code generation

I'm generating code in a visual studio extension using CodeDom and plain code strings. My extension reads a current classes declared fields and properties using reflection and generates contructors, initializers, implements certain interfaces, etc.
The generator class is simple:
public class CodeGenerator < T >
{
public string GetCode ()
{
string code = "";
T type = typeof(T);
List < PropertyInfo > properties = t.GetProperties();
foreach (PropertyInfo property in properties)
code += "this." + property.Name + " = default(" + property.PropertyType.Name + ")";
}
}
I'm stuck at field and property initializers in two ways.
Firstly, although default(AnyNonGenericValueOrReferenceType) seems to work in most cases, I'm uncomfortable with using it in generated code.
Secondly, it does not work for generic types since I can't find a way to get the underlying type of the generic type. So if a property is List < int >, property.PropertyType.Name returns List`1. There are two problems here. First, I need to get the proper name for the generic type without using string manipulation. Second, I need to access the underlying type. The full property type name returns something like:
System.Collections.Generic.List`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
Before I try to answer, I feel compelled to point out that what you're doing seems redundant. Assuming that you are putting this code into a constructor, generating something like:
public class Foo
{
private int a;
private bool b;
private SomeType c;
public Foo()
{
this.a = default(int);
this.b = default(bool);
this.c = default(SomeType);
}
}
is unnecessary. That already happens automatically when a class is constructed. (In fact, some quick testing shows that these assignments aren't even optimized away if they're done explicitly in the constructor, though I suppose the JITter could take care of that.)
Second, the default keyword was designed in large part to do exactly what you're doing: to provide a way to assign the "default" value to a variable whose type is unknown at compile time. It was introduced for use by generic code, I assume, but auto-generated code is certainly correct in using it as well.
Keep in mind that the default value of a reference type is null, so
this.list = default(List<int>);
does not construct a new List<int>, it just sets this.list to null. What I suspect you want to do, instead, is to use the Type.IsValueType property to leave value types at their default values, and initialize reference types using new.
Lastly, I think what you're looking for here is the IsGenericType property of the Type class and the corresponding GetGenericArguments() method:
foreach (PropertyInfo property in properties)
{
if (property.Type.IsGenericType)
{
var subtypes = property.Type.GetGenericArguments();
// construct full type name from type and subtypes.
}
else
{
code += "this." + property.Name + " = default(" + property.PropertyType.Name + ")";
}
}
EDIT:
As far as constructing something useful for a reference type, a common technique I've seen used by generated code is to require a parameterless constructor for any class that you expect to use. It's easy enough to see if a class has a parameterless constructor, by calling Type.GetConstructor(), passing in an empty Type[] (e.g. Type.EmptyTypes), and see if it returns a ConstructorInfo or null. Once that has been established, simply replacing default(typename) with new typename() should achieve what you need.
More generally you can supply any array of types to that method to see if there's a matching constructor, or call GetConstructors() to get them all. Things to look out for here are the IsPublic, IsStatic, and IsGenericMethod fields of the ConstructorInfo, to find one you can actually call from wherever this code is being generated.
The problem you are trying to solve, though, is going to become arbitrarily complex unless you can place some constraints on it. One option would be to find an arbitrary constructor and build a call that looks like this:
var line = "this." + fieldName + " = new(";
foreach ( var param in constructor.GetParameters() )
{
line += "default(" + param.ParameterType.Name + "),";
}
line = line.TrimEnd(',') + ");"
(Note this is for illustrative purposes only, I'd probably use CodeDOM here, or at least a StringBuilder :)
But of course, now you have the problem of determining the appropriate type name for each parameter, which themselves could be generics. And the reference type parameters would all be initialized to null. And there's no way of knowing which of the arbitrarily many constructors you can pick from actually produces a usable object (some of them may do bad things, like assume you're going to set properties or call methods immediately after you construct an instance.)
How you go about solving those issues is not a technical one: you can recursively apply this same logic to each parameter as far down as you're willing to go. It's a matter of deciding, for your use case, how complex you need to be and what kind of limits you're willing to place on the users.
If you are sure you want to use strings, you will have to write your own method to format those type names. Something like:
static string FormatType(Type t)
{
string result = t.Name;
if (t.IsGenericType)
{
result = string.Format("{0}<{1}>",
result.Split('`')[0],
string.Join(",", t.GetGenericArguments().Select(FormatType)));
}
return result;
}
This code assumes you have all necessary usings in your file.
But I think it's much better to actually use CodeDOM's object model. This way, you don't have to worry about usings, formatting types or typos:
var statement =
new CodeAssignStatement(
new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), property.Name),
new CodeDefaultValueExpression(new CodeTypeReference(property.PropertyType)));
And if you really don't want to use default(T), you can find out whether the type is a reference or value type. If it's a reference type, use null. If it's value type, the default constructor has to exist, and so you can call that.

Categories