I have a function that returns an anonymous type which I want to test in my MVC controller.
public JsonResult Foo()
{
var data = new
{
details = "something",
more = "More"
};
return Json(data);
}
I want to verify the data I get from the Foo function, What I'm doing now is getting the data type and get it's properties values with reflection.
[Test]
public void TestOne()
{
var data = _controller.Foo().Data;
var details = data.GetType().GetProperty("details").GetValue(data, null);
var more = data.GetType().GetProperty("more").GetValue(data, null);
Assert.AreEquals("something", details);
Assert.AreEquals("More", more);
}
Is there a simple way similar to this to check the anonymous properties?
[Test]
public void TestTwo()
{
var data = (dynamic) _controller.Foo().Data;
var details = data.details; // RunTimeBinderException object does not contain definition for details
var more = data.more;
Assert.AreEquals("something", details);
Assert.AreEquals("More", more);
}
Anonymous objects are internal, which means their members are very restricted outside of the assembly that declares them. dynamic respects accessibility, so pretends not to be able to see those members. If the call-site was in the same assembly, I expect it would work.
Your reflection code respects the member accessibility, but bypasses the type's accessibility - hence it works.
In short: no.
This blog had a working answer: http://blog.jorgef.net/2011/06/converting-any-object-to-dynamic.html - Thanks #Jorge-Fioranelli.
public static class DynamicExtensions {
public static dynamic ToDynamic(this object value) {
IDictionary<string, object> expando = new ExpandoObject();
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType()))
expando.Add(property.Name, property.GetValue(value));
return expando as ExpandoObject;
}
}
Anonymous type is a regular static type in .NET, it's just that you do not give it a name (a compiler, however, does). That's why casting it to dynamic will not work. However, if you have control over Foo(), you can construct and return a dynamic object instead of anonymous, and then your code is going to work. This should do the trick:
dynamic JsonResult Foo() {
dynamic data = new ExpandoObject();
data.details = "something";
data.mode = "More";
return Json(data);
}
As suggested by #TrueWill and #Marc Gravell, who also referred to this blog post
Since this is for unit testing, you could use InternalsVisibleTo. See Anonymous Types are Internal, C# 4.0 Dynamic Beware! Thanks to #MarcGravell for pointing out that anonymous objects are internal!
Bottom line: Set up an [assembly: InternalsVisibleTo("foo")] mapping if you want to share an anonymous object from one assembly to another. In the OP case, it would be a matter of setting this in the MVC controller project, referring to the test project. In my specific case, the other way around (since I'm passing an anonymous object from my test project into the "production code" project).
The easiest way in that "other project" to be able to use it is definitely to cast it to dynamic and then just use the properties like normal. It does work, no problems whatsoever.
So, bottom line: I feel that Marc Gravell's answer is slightly incorrect; this can clearly be done
(iff the projects in question are modifiable by you, so you can set up the InternalsVisibleTo mapping accordingly, and this does not pose a problem for whatever other reason).
You can use NewtonSoft or the Asp.net MVC libraries:
var data = Json.Decode(Json.Encode(_controller.Foo().Data));
var data=JsonConvert.DeserializeObject<Dictionary<string,object>>(JsonConvert.SerializeObject((_controller.Foo().Data))
Related
What is the best general purpose way to get a System.Type from Microsoft.CodeAnalysis.ISymbol for different types of symbols ? (e.g. class declarations, variable, properties, etc)
I want to be able to do various checks on the type e.g. as checking if the type implements any interface or is cast-able to any interface, just like one can check on System.Type.
The problem I am having is that most of the concrete classes used to represent the symbol are internal (see http://sourceroslyn.io/) and I could not find tye type information in the ISymbol.
SourceNamedTypeSymbol
LocalSymbol
I retrieve the ISymbol using the following code
var objectSymbol = (ISymbol)model.GetDeclaredSymbol(obj.Node);
Short answer: you can't. There is no proper way to get a System.Type (reflection) from an ISymbol (Roslyn).
One option to do go in the direction you want is constructing the fully-qualified name of your type and then looking that up through reflection (example).
You should probably ask yourself whether this is something you need to do in the first place though -- reflection and Roslyn aren't really intended to work together.
What you are interested in, however, can be done through Roslyn as well. The key here is using the semantic model which has all this information for you.
All declarations (opposed to usages) have a specific overload available that allows you to get the declaring symbol and return it in the appropriate type (such as INamedTypeSymbol in this case).
Take the following example:
const string source = #"
using System;
namespace MyNamespace
{
class MyClass : IDisposable
{
void Method()
{
MyClass nameOfVariable, another;
}
}
}
";
var tree = CSharpSyntaxTree.ParseText(source);
var compilation = CSharpCompilation.Create("MyCompilation", new[] { tree }, new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) });
var semanticModel = compilation.GetSemanticModel(tree);
var root = tree.GetRoot();
var classSymbol = semanticModel.GetDeclaredSymbol(root.DescendantNodes().OfType<ClassDeclarationSyntax>().First());
Console.WriteLine(string.Join(", ", classSymbol.AllInterfaces));
This will display all the interfaces the class implements. Keep in mind however that this just refers to the current definition -- if you're also interested in base types you'll have to go through the hierarchy yourself.
In your scenario you should be able to just cast it to the right type (assuming you are checking a declaration node):
var objectSymbol = (INamedTypeSymbol) model.GetDeclaredSymbol(obj.Node);
I think this is what you are looking for:
var castedProperty = (IPropertySymbol) property;
var type = castedProperty.Type.Name;
The variable 'property' is an ISymbol instance.
I have a function that returns an anonymous type like so (simplified for illustrative purposes)...
public object GetPropertyInfo()
{
return new {
PropertyName = "Foo",
Value = "Laa"
};
}
When I do this...
dynamic pi = GetPropertyInfo();
Console.WriteLine(pi);
It outputs this (the same as if I did '?pi' in the immediate window)...
{ PropertyName = "A", Value = 44 }
PropertyName: "A"
Value: 44
But if I try doing this...
string propertyName = pi.PropertyName;
...it compiles but throws a runtime exception saying
Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in System.Core.dll
Additional information: 'object' does not contain a definition for 'PropertyName'
What gives? What am I missing here?
The problem is that anonymous types are internal, which means that you can't access their properties with dynamic property accessors from projects other than the one they were created in. The dynamic binding treats them as the closest public inherited type it knows about--object.
To fix this, you can declare a public type to represent the values you're expecting to find in your anonymous type. This is probably a good idea anyway, since you're clearly expecting to consume the returned properties in other parts of your code. Using a declared type also enables you to maintain type-safety, avoiding the need for dynamic entirely.
If you absolutely must use dynamics here, the next best option is probably to change your AssemblyInfo.cs file to make internal properties accessible to the project you're trying to access them from:
[assembly:InternalsVisibleTo("MyOtherProject")]
Edit
According to your edit. Apparently you are not required dynamic at all as there are no dynamic properties. Just create a concrete type with your predefined properties. It's better to avoid dynamic when possible anyway.
Old Answer
You need to use an ExpandoObject. Reference here.
In fact, GetPropertyInfo() should return an ExpandoObject.
dynamic foo = this.GetPropertyInfo();
string i = foo.MyPropertyName;
private ExpandoObject GetPropertyInfo()
{
dynamic obj = new ExpandoObject();
obj.PropertyName = "MyPropertyName";
obj.PropertyType = "MyPropertyType";
return obj;
}
The ExpandoObject class enables you to add and delete members of its
instances at run time and also to set and get values of these members.
This class supports dynamic binding, which enables you to use standard
syntax like sampleObject.sampleMember instead of more complex syntax
like sampleObject.GetAttribute("sampleMember").
Also, you can use System.Reflection
object D = GetPropertyInfo();
Type t = D.GetType(); // get object's type
PropertyInfo p = t.GetProperty("PropertyName"); // look up for the property:
object P = p.GetValue(D, null); // get the value
Fiddle demo
I search on Google but the result is misunderstand.
This is a code flow:
public class Store
{
public dynamic GetList(List<string> propertyFields)
{
// Body here
// for in list propertyFields. Such as: ["Code", "Name", "Address", ...]
// dynamic result = ...
// result.Code = "value", result.Name = "abc", result.Address = "homeless", result.... = "..."
// return result
}
}
Method returns a dynamic object.
propertyFields is a list of fields name. When I pass 4 strings in list, dynamic has 4 property fields with value (later).
When I call this method:
Store store = new Store();
var rs = store.GetList(["Code","Name","Address"])
Console.WriteLine(rs[0].Code)
That is my point.
My question: Is it possible to do that in C#?
You have confused dynamic, which is a compiler feature that means "defer type analysis of uses of this object until runtime" with ExpandoObject which means "an object that can have properties added at runtime".
It is an understandable confusion; many languages that lack static type checking also have expando objects.
You need to take a look to ExpandoObject class.
Here is more detailed answer to your question:
Dynamic class creation
What are the true benefits of ExpandoObject?
We're developing something like a Spec-framework (e.g. MSpec, NSpec, etc.) and want to distinguish methods within a specification class at runtime:
public class AccountSpecs
{
private Account sut; // subject under test
Given an_account() { sut = new Account(); }
When changing_owner()
{
var result = sut.ChangeOwner("new owner");
It["returns_previous_owner"] = () => result.ShouldBe("old owner");
}
}
As you can see this class is not compileable because an_account() and changing_owner() do not have return statements.
Q1: I guess there is absolutely no way in C# to specify that "return null" is used by default if no return statement is given?
As there are no global type aliases (something like typedef When as System.Void) we are forced to actually introduce the classes Given and When and force our users to return something in this methods.
We use the return statement in the When methods for either When.ENABLED or When.DISABLED("reason") to temporarily disable specs.
In the "given methods" we want to return the subject under test. We want to enable the following:
Given an_account() { sut = new Account(); return sut; }
However: "Cannot convert expression type ... to return type ..."
Next up we thought about an implicit conversion operator for any object to Given, however this isn't allowed in C# either, see: cs0553 user-defined conversion from base class not allowed
Q2: So is there any workaround for this to work or is the return-type-distinguishing-idea doomed?
There are lots of options if you change your design a little.
You can add a porperty to Given type that will hold a refernce to any object, so that an_account will return Given(sut)
You can return plain object from an_account and mark the method with [Given] attribute
You can also get rid of this method-in-the-class approach and just use a builder pattern with fluent interface, like linq, to create a test definition.
Like this:
new Test()
.Given(() =>new Account())
.When(()=> ...);
Let me start by saying I'm pretty new to using interfaces.
I'm writing a method (GetClaimDetails) that will return information about a medical insurance claim. If it is claim type A, it will return an list of the ClaimDetailA class. If claim type B, return list of ClaimDetailB class. Both of these classes share common properties but each have unique properties. The common properties are implemented in an interface.
I extracted an interface named IClaimDetail and set both to implement it. When i set the method to return IClaimDetail and have it return an instance of an object that implements IClaimsDetail, I get the compiler message
'Cannot implicitly convert type 'System.Collections.Generic.List DentalClaimDetail' to 'System.Collections.Generic.List IClaimDetail'
private static List<IClaimDetail> GetClaimDetailsB(string claimNumber, string connectionStringName)
{
var claimReportRows = new List<DentalClaimDetail>();
..removed for brevity
return claimReportRows;
}
public class DentalClaimDetail : IClaimDetail
{
...
}
When a method returns an interface, you just return an object the implements the interface. Correct? What am I doing wrong?
var claimReportRows = new List<IClaimDetail>();
Just change this. Then you will be able to insert DentalClaimDetail into it still.
Generics actually generate an type on-the-fly at compile time for every generic argument, so List<IClaimDetail> is one type, and List<DentalClaimDetail> is actually another type, so you will get compiler errors for that.
Yes, lame, but simply changing your call as outlined by Daniel A. White
var claimReportRows = new List<IClaimDetail>();
(although you should just be able to use the type directly unless you are using Linq) and then having the code use casting to cast the DentalClaimDetail to an IClaimDetail should do the trick.
If not using Linq, you can do something like:
List<IClaimDetail> claimReportRows = new List<IClaimDetail>();
//...populate Dentail Claims Here...
foreach(DentalClaimDetail dcd in dentalClaims)
{
claimReportRows.Add((IClaimDetail)dcd);
}
return claimReportRows.
Hope this helps!