I have a dynamic object in C# that I'd like to convert to a static object. I wrote a function that takes the dynamic type and returns the static type, but it actually returns dynamic, ignoring the specified return type. (This is standard behavior, as I've now discovered.) AutoMapper doesn't handle dynamic types. How can I properly convert dynamic to static?
Using some serializers can be a solution. Suppose you form a dynamic object like
dynamic d = new ExpandoObject();
d.a = 1;
d.b = new ExpandoObject();
d.b.c = "222";
and you want to cast this to A
public class A
{
public int a { set; get; }
public B b { set; get; }
}
public class B
{
public string c { set; get; }
}
You can use, for example, Json.Net, to do this serialization/deserialization
A a = JsonConvert.DeserializeObject<A>(JsonConvert.SerializeObject(d));
If you got the type, you can instanciate a new object, then copy the state of your dynamic object into this object with the FormatterServices class:
var staticObject = Activator.CreateInstance(yourType);
MemberInfo[] members = FormatterServices.GetSerializableMembers(yourType);
FormatterServices.PopulateObjectMembers(staticObject, members,
FormatterServices.GetObjectData(dynObject, members));
I'm confused... I thought that .NET should already do this for you. Here's some test code and it fits with my expectations:
class Program
{
static void Main(string[] args)
{
dynamic anythingGoes = 1;
var convertedToInt = ConvertToType<int>(anythingGoes);
// expectation: should output Int32. and it does....
Console.WriteLine(convertedToInt.GetType().Name);
anythingGoes = "ribbit";
var convertedToString = ConvertToType<string>(anythingGoes);
// expectation: should output String. and it does also...
Console.WriteLine(convertedToString.GetType().Name);
Console.ReadLine();
}
// just a small method to cast the dynamic to whatever i want
// ...only for this test. not guaranteed to be crash safe. in fact, don't assume!
static T ConvertToType<T>(dynamic obj)
{
T result = obj;
return result;
}
}
Related
I'm trying to convert some anonymous type back to its original strong type class.
I have some legacy code (which I cannot touch) which create an anonymous class:
public class Cat : FooId
{
public int Id { get; set; }
public string Name { get; set; }
}
var result = new
{
Id = Mapper.Map<TFooId>(someCat)
};
NOTE: I've tried to make this fake class and interface similar to my code.
This then gives me:
result.GetType().ToString() : <>f__AnonymousType1``1[MyProject.Cat]
From here, I'm not sure how to convert this back to a MyProject.Cat instance?
I've tried (and fails):
(MyProject.Cat)result
(dynamic)result
but both fail. The dynamic doesn't throw an error ... but I can't access any properties in it.
C# is a statically typed language, and those two types are not in any way related to one another. Unless you're able to modify the code which defines those types, the way you'd convert from one to the other would be to create a new instance of the target type and populate it from the source object.
For example:
var resultCat = new Cat { Id = result.Id };
Edit: From comments it looks like it may be possible that the Id property on the result object may be an instance of Cat or some other object? You're going to need to do some debugging to find out what your types are.
But the overall concept doesn't really change. If you have an instance of Cat in your results then you can use that instance. If you don't then in order to create one you'd need to create a new instance and populate it with the data you have. Even if two types are intuitively or semantically similar, they are different types.
It's true what David said with regard to the fact that C# is a statically-typed language and that the new instance should be populated from the source the way he suggested.
However, there are work-arounds (though less performant) for that, such as reflection.
Consider you have a console app where you have defined ObjectExtensions as follows:
public static class ObjectExtensions
{
public static TOut Map<TOut>(this object #in)
where TOut : new()
{
TOut #out = new TOut();
if (#in?.GetType() is Type tin)
{
Type tout = typeof(TOut);
foreach ((PropertyInfo pout, PropertyInfo pin) in tout.GetProperties().Join(tin.GetProperties(), pi => pi.Name, pi => pi.Name, (pout, pin) => (pout, pin)))
{
pout.SetValue(#out, pin.GetValue(#in));
}
}
return #out;
}
}
And Class1 as follows:
public class Class1
{
public string A { get; set; } = "A";
public string B { get; set; } = "B";
public string C { get; set; } = "C";
public override string ToString()
{
return $"{{A={A}, B={B}, C={C}}}";
}
}
You will be able to map your anonymous type back to its original strongly-typed class like this:
Console.WriteLine(new { A = "Anonymous A", B = "Anonymous B", C = "Anonymous C" }.Map<Class1>());
Therefore the bloc above should show the following output:
{A=Anonymous A, B=Anonymous B, C=Anonymous C}
In this case, of course, I have assumed that Class1 (Cat in your example) must have a public parameterless constructor. That may not always be the case. There are more sophisticated scenarios of course that might involve other techniques for creating the object such as cloning or dependency injection. Just saying that the idea of yours is possible.
I want to write a generic function, to loop through several different objects, that have one field in common. I want to change this field on all of the objects.
However, I need the types of each of the objects in the generic function.
My code looks like this:
UpdateObjects<objectType>(IMyCollection collection) {
foreach (objectType obj in collection)
{
var correctlyTypedObject = (objectType)obj.MakeEditable();
// Do stuff with correctlyTypedObject
}
}
The MakeEditable() changes the type of the obj, so I need to cast it back.
Is there a way to do this?
I call the function as follows:
UpdateObjects<userObject>(collection);
Since I call the function with type userObject, I figured you could use that type to cast objects within the function itself. Is this assumption correct?
I don't know if I understand your problem completely, but it seems to me you are looking for what dynamic offers.
Assuming three classes A,B,C which all have property P.
class A { public int P { get; set; } }
class B { public int P { get; set; } }
class C { public int P { get; set; } }
Then a function could look like this:
private void UpdateObjects(dynamic[] collection)
{
int newValue = 123456;
foreach (dynamic obj in collection)
{
obj.P = newValue;
}
}
Could be used like this:
dynamic[] collection = new dynamic[] {new A(), new B(), new C()};
UpdateObjects(collection);
// Result
foreach (dynamic o in collection)
{
int p = o.P;
Debug.WriteLine(p);
}
This question already has answers here:
Using Json.NET converters to deserialize properties
(9 answers)
Closed 6 years ago.
Is there a way to serialize and then deserialize a class that has a member variable of unknown type that could be either be a simple value type or an instance of the containing class itself ?
public class A
{
public dynamic Value { get; set; }//Value could be int or type A for example
}
public static class ASerializer
{
public static string ToJson(A table)
{
return JsonConvert.SerializeObject(table);//using Json.Net
}
public static A FromJson(string json)
{
return JsonConvert.DeserializeObject<A>(json);
}
}
public class Tests
{
public static void TestASerialization()
{
var a = new A() { Value = 1 };
var aa = new A { Value = a };
var aaa = new A { Value = aa };
var json = ASerializer.ToJson(aaa);
var aaa2 = ASerializer.FromJson(json);
var aa2 = (A)aaa2.Value; //throws
}
}
if I serialize and then deserialize aaa - I can't cast the Value of the deserialized aaa back to type A I get:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException : Cannot convert type 'Newtonsoft.Json.Linq.JObject' to
'A'
Any suggestions on handling this nested hierarchy elegantly, without resorting to hand coding ?
Seems to work with just one instance of A with Value of type A.
You aren't casting what you think you're casting.
In this case, you're actually casting the Value property to A. You need to wrap the aaa2 instance in params with the cast before accessing the property.
var aa2 = ((A)aaa2).Value;
Dynamic is a compiler hack mostly, I would recommend generics instead.
#David L 's answer is also correct.
public class A<T>
{
public T Value { get; set; }
}
I need to access a property by an index or something similar. The reason why is explained in this already answered question. That answer uses Linq and I prefer something without that dependency. I have no control over the class.
public class myClass
{
private string s = "some string";
public string S
{
get { return s; }
}
}
class Program
{
static void Main(string[] args)
{
myClass c = new myClass();
// I would like something similar
// or same functionality
string s = c["S"];
}
}
As you have no control over the class you can use extension method and reflection to get property value by name:
static class ObjectExtensions
{
public static TResult Get<TResult>(this object #this, string propertyName)
{
return (TResult)#this.GetType().GetProperty(propertyName).GetValue(#this, null);
}
}
Usage:
class A
{
public string Z
{
get;
set;
}
public int X
{
get;
set;
}
}
class Program
{
static void Main(string[] args)
{
A obj = new A();
obj.Z = "aaa";
obj.X = 15;
Console.WriteLine(obj.Get<string>("Z"));
Console.WriteLine(obj.Get<int>("X"));
Console.ReadLine();
}
}
use (EDIT - as per comment):
string s = c.GetType().GetProperty ("S").GetGetMethod().Invoke (c, null).ToString();
It gives you the value of the (public) property named S of the the instance c regardless of the type of c and doesn't use LINQ at all although I must admit that I don't see why LINQ should be a problem...
You can achieve the same thing by using a default property on your class and a collection. Provided that you will always want strings, you could use the Dictionary class as your default property.
Then in the constructor you could intialize myDictionary["s"] = "some string";
You could then use the myClass as a collection, so myClass["s"] would return "some string".
Reflection is usually an indicator that you haven't created an API to do the job you need, if you have the code to modify then I recommend you use the default property.
See this MSDN article:
How can I use reflection to create a generic List with a custom class (List<CustomClass>)? I need to be able to add values and use
propertyInfo.SetValue(..., ..., ...) to store it. Would I be better off storing these List<>'s as some other data structure?
Edit:
I should have specified that the object is more like this, but Marc Gravell's answer works still.
class Foo
{
public List<string> Bar { get; set; }
}
class Foo
{
public string Bar { get; set; }
}
class Program
{
static void Main()
{
Type type = typeof(Foo); // possibly from a string
IList list = (IList) Activator.CreateInstance(
typeof(List<>).MakeGenericType(type));
object obj = Activator.CreateInstance(type);
type.GetProperty("Bar").SetValue(obj, "abc", null);
list.Add(obj);
}
}
Here's an example of taking the List<> type and turning it into List<string>.
var list = typeof(List<>).MakeGenericType(typeof(string));