Get access to inner object to check if they are the same - c#

I am working on a unit test where I want to assert that the object coming back is the same as the model.
var actual = scope.InstanceUnderTest.GetContent(expectedId);
var newFileStreamer = new FileStreamer(scope.TestDocument.Data, "application/octet-stream");
Assert.IsTrue(actual.Result.Equals(newFileStreamer));
actual.Result appears to be one level away from the object that is the same as newFileStreamer:
How do I get access to the inner filestream object to check if they are the same?

It is not one level away, the debugger shows it that way because it performs a cast to the correct type. If you right-click on the second-node and select add-watch you will see that the expression watched contains a cast.
To check for the internals you could use reflection.
Note that is not recomended to test for private field in unit testing, but if you really want to, here is some code:
var actual = scope.InstanceUnderTest.GetContent(expectedId);
var type = actual.Result.GetType();
var dataField = type.GetField("_data",
BindingFlags.NonPublic |
BindingFlags.Instance);
var contentTypeField = type.GetField("_contentType",
BindingFlags.NonPublic |
BindingFlags.Instance);
Assert.IsTrue(dataField.GetValue(actual.Result) == scope.TestDocument.Data);
Assert.IsTrue(contentTypeField.GetValue(actual.Result) == "application/octet-stream");

The default behavior for .Equals() for reference types is to check for reference equality (i.e. do they point to the same object on the heap). Since one of the two objects you instantiate just before your assert then there is no way they would ever be considered the same object (since there is no way for another object to get a reference to newFileStreamer between its instantiation and the assert).
If you have not yet provided an overload for .Equals for your fileStreamer type then you can solve your problem by doing so and stating within the method what exactly would constitute being equal.

Based on the comments it seems like this should be fine:
if( (FileStreamer)actual.Result == newFileStreamer) {
//do work here
}
Or I guess
if( (actual.Result as FileStreamer) == newFileStreamer) {
//do work here
}

Related

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.

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.

Protobuf.net 'IsDefined' logical bug?

In the following code snippet I'm trying to use the 'IsDefined' method of a purpose-created model to see if I've already added the given type to the model. However, it always returns true, and inspection of the types known to the model after calling IsDefined shows that the type has been added to the model during the call. This seems to make IsDefined redundant, or am I missing something?
Version is 2.0.0.668.
private static void FillSignatureModel(RuntimeTypeModel Model, Object SignedObject) {
var lBinding = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
var lType = SignedObject.GetType();
// Already sorted
if (Model.IsDefined(lType)) return;
var lProtoType = Model.Add(lType, false);
...
Secondary question: Is there a better way of reporting Protobuf.net bugs - not that I ever expected to need one ;-)

Comparing the value of a property in two instances

I think I'm having boxing issues
foreach(var p in item.GetType().GetProperties().
Where(p => p.GetValue(original, null) is ValueType))
{
var originalValue = p.GetValue(original, null);
var modifiedValue = p.GetValue(item, null);
if (!originalValue.Equals(modifiedValue))
kvpData.AppendFormat("{0}={1}&", p.Name, originalValue);
}
originalValue is never equal to modifiedValue, Im guessing it's because they are boxed inside Object. But how do I fix it?
It is not a boxing issue. Equals is a virtual method, which the boxed value types override just fine.
However, I am not sure what the issue is. Could it be that there aren’t actually any matching properties? Remember that GetProperties() without any parameters will only return public properties. If the properties you need are private, you need to add some BindingFlags:
GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
(I’m assuming here that you don’t want static properties.)
Are you also sure that it is actually properties that you are after and not fields? Remember that if you declare something as
public string Name;
then it’s a field, whereas
public string Name { get; set; }
is a property. If it’s actually fields you need, you need to use GetFields() instead of GetProperties() with the same binding flags.
Linq is a great tool, but I'm not sure why you're using it here. You're actually causing the set of properties to get iterated twice, which is very expensive. I'd write the code without Linq. Also, there's no need to get the value more than once, which is again very expensive. Give this code a try. It avoids the flaws I pointed out and was comparing correctly when I made and tested a dummy class with it:
foreach(PropertyInfo p in item.GetType().GetProperties())
{
if (p.PropertyType.BaseType == typeof(ValueType) || p.PropertyType == typeof(string))
{
var originalValue = p.GetValue(original, null);
var modifiedValue = p.GetValue(item, null);
if (originalValue != modifiedValue) kvpData.AppendFormat("{0}={1}&", p.Name, originalValue);
}
}
Also, note that strings are not a ValueType although they do implement a value comparison.
From MSDN: Object.Equals :
The default implementation of Equals supports reference equality for
reference types, and bitwise equality for value types. Reference
equality means the object references that are compared refer to the
same object. Bitwise equality means the objects that are compared have
the same binary representation.
That means that in your case this 2 objects (if they are reference types) are never point to the same instance.
There is no an easy way to resolve this in so generic way as you would like to do.
But you can implement (just an example) an IComparable on those types you gonna to compare, and after in this iteration check if the type of the value rturned implements that interface, so cast and call it's implemented IComparable.CompareTo method.
You can check if the object implements specified interfacce, in this current case IComparable, you can do something like this:
originalValue .GetType().GetInterfaces().Any(x =>
x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IComparable))
Hope this helps.

How do you dynamially invoke a property, but only if its argument is a certain type?

I am trying to use reflection to get all the (settable) properties in my POCO (which take a string argument, for now, but I plan to expand to other types), and set them to something arbitrary. (I need to make sure the .Equals method is implemented properly.)
I have some code in my unit tests that looks something like this (where t is the object under test, and u is a default version of that object):
foreach(var property in t.GetType().GetProperties())
{
var setMethod = property.GetSetMethod();
var type = setMethod.GetParameters()[0].GetType();
if(typeof(string).IsAssignableFrom(type))
{
setMethod.Invoke(t, new object[] {"a"});
Assert.IsFalse(t.Equals(u));
Assert.IsFalse(t.GetHashCode() == u.GetHashCode());
}
}
The place where this fails is where I say typeof(string).IsAssignableFrom(type). The code inside the if { ... } block never runs. How would I properly code up this part of the test?
You have confused ParameterInfo.GetType() with ParameterInfo.ParameterType. You should have:
var type = setMethod.GetParameters()[0].ParameterType;
.GetType() returns the Type of the current object, in this case ParameterInfo, which is obviously not what you want.

Categories