How to pass the current instance to FieldInfo.GetValue inside the instance? - c#

I'm making an abstract class that I need to validate fields in it's descendants. All the validated fields are marked by an attribute and are suppose to be checked for nulls or empty. To do that I get all the fields in the class:
var fields = this.GetType().GetFields().Where(field => Attribute.IsDefined(field, typeof(MyAttribute))).ToList();
And then, for every FieldInfo I try to do this:
if (string.IsNullOrEmpty(field.GetValue(this).ToString()))
{
// write down the name of the field
}
I get a System.NullReferenceException: object reference not set to an instance of an object.
I know I am suppose to pass the instance of a class to the GetValue method. But how can I pass the current instance (the one that's launching the logic)?
Or: Is there an other way of getting the field's value?

As Lucas says, the problem will be calling ToString() when you shouldn't. Presumably your attribute should only be applied to string fields anyway, so the simplest approach is just to cast the result to string. If that cast fails, it indicates a bigger bug (the attribute being applied incorrectly).
if (string.IsNullOrEmpty((string) field.GetValue(this)))

The GetValue call is fine. The problem lies in the return value on which you're calling ToString.
If GetValue returns null, then ToString will be called on this null value, and this will throw the NullReferenceException.
Do something like this instead:
var value = field.GetValue(this);
if (value == null || string.IsNullOrEmpty(value.ToString()))
{
// write down the name of the field
}

Related

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).

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

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.

How to check if deserealized class members have value?

I have an initial snippet which deserealized parameters, checks for value and handles the error:
var param = js.Deserialize<int?>(jqData.Params);
if (param.HasValue)
{
resp.ReturnValue = param.Value;
}
else
{
//handle error code
}
Now, during my modification, I have changed the method to accept a list of class parameters instead of nullable integers
var param = js.Deserialize<ClassName>(jqData.Params);
Now it invalidates .HasValue and .Value methods.
My question is: How do I properly modify these two lines so it would hold the same meaning as initial if statement?
Thus far I only thought about switching to if (param != null), but I cannot think of proper equivalent to .Value.
As soon as ClassName is a class (see - a reference type) you just need to check if it is not null.
If it is not - then the variable holds a reference to an object that you use as-is.

Generic method returns nullReferenceException

I have this Generic Method that always returns a nullReferenceException. I've taken all the unnecessary code out, and it still give me the exception.
public T RetrieveInformationFromApi<T>(int Id) where T : IMovie
{
T result = default(T);
result.Title = "test";
}
The method can be called with three different classes that all have the attribute Title and the all implement the interface IMovie but the method still give me an exception. What am i doing wrong?
You should add a constructor constraint on you T parameter so you can create a new instance.
public T RetrieveInformationFromApi<T>(int Id) where T : IMovie, new()
{
T result = new T();
result.Title = "test";
}
You're using default which returns null for reference types (and I'm guessing you're using a reference type.
From MSDN:
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.
I'm not sure what you're trying to achieve but this way you will always get that exception for reference types.
When the T is a reference type (class), the default (T) returns null, as it is the default value of all reference types.
Then obviously trying to access its property results in NullReferenceException

Writing a certain generic method

I have a series of methods to write, but I think there is some commonality (well, I know there is). The method I'd like to see will take two things, an object and... well, I'm not so sure about the second one, but probably a string.
The object should be generic, although it can only be from a set list (in this case, that commonality seems to be that they inherit from both INotifyPropertyChanging and INotifyPropertyChanged interfaces).
The string should be the name of a property within the generic object. It should be checked to see if that property exists within that object before being put into use (it would be used as a way to compare the objects by that given property).
So I guess the process would be... generic object gets passed into method (along with property name string). A check to see if the object contains the property. If it does, continue and somehow have access to 'object.PropertyName' where 'PropertyName' was the supplied string.
I don't know if it's easy or possible or even wise, but I know that it would save me some time.
Thanks in advance for any advice you might be able to offer with this.
Edit: Thanks for the all the replies so far guys. Let me clarify some things:
Clarification of 'access'
When I said, "... and somehow have access to 'object.PropertyName'", what I meant was that the method should be able to use that property name as if it were just a property of that object. So, let's say the string passed in was "ClientName", there would be the ability to read (possibly write, although at the moment I don't think so as it's just a check) object.ClientName, if it was determined that existed.
What I'm trying to do
I have a WCF service which accesses an SQL database using Linq. The objects I spoke of are entities, generated from the program SQLMetal.exe, so my objects are things like 'Client', 'User' and this sort of thing. I wrote a method which took a List of entities. This method added only those entities which did not exist within the collection (some could have been duplicates). It figured out which ones were duplicates by checking a property within the entity (which corresponds to data in a column of the database). It's that property which I figured might be variable.
It sounds like you don't really want to check if it's a certain type, and if that is so then you don't have to and its actually easier not to check the type. This shows how to check if the property exists and if it is readable and writeable and shows how to use it after it's found:
private void Form1_Load(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder();
PropertyInfo info = GetProperty(sb, "Capacity");
//To get the value of the property, call GetValue on the PropertyInfo with the object and null parameters:
info.GetValue(sb, null);
//To set the value of the property, call SetValue on the PropertyInfo with the object, value, and null parameters:
info.SetValue(sb, 20, null);
}
private PropertyInfo GetProperty(object obj, string property)
{
PropertyInfo info = obj.GetType().GetProperty(property);
if (info != null && info.CanRead && info.CanWrite)
return info;
return null;
}
I think only indexer properties can take parameters in C#. And I believe if you wrote properties in VB that take parameters and tried to reference that assembly in C# they would show up as methods instead of properties.
You could also write a function like this that would take 2 objects and a string for a property name and return the result of those properties matching:
private bool DoObjectsMatch(object obj1, object obj2, string propetyName)
{
PropertyInfo info1 = obj1.GetType().GetProperty(propertyName);
PropertyInfo info2 = obj2.GetType().GetProperty(propertyName);
if (info1 != null && info1.CanRead && info2 != null && info2.CanRead)
return info1.GetValue(obj1, null).ToString() == info2.GetValue(obj2, null).ToString();
return false;
}
Comparing the values of the properties might be tricky because it would compare them as objects and who knows how equality will be handled for them. But converting the values to strings should work for you in this case.
If you know the 2 objects are the same type then you can simplify it:
private bool DoObjectsMatch(object obj1, object obj2, string propetyName)
{
PropertyInfo info = obj1.GetType().GetProperty(propertyName);
if (info != null && info.CanRead)
return info.GetValue(obj1, null).ToString() == info.GetValue(obj2, null).ToString();
return false;
}
I think you're looking for something like:
public void SomeMethod<T>(T object, string propName)
where T : INotifyPropertyChanging, INotifyPropertyChanged
(
var type = typeof(T);
var property = type.GetProperty(propName);
if(property == null)
throw new ArgumentException("Property doesn't exist", "propName");
var value = property.GetValue(object, null);
)

Categories