Cast ExpandoObject to anonymous type - c#

Can I cast ExpandoObject to anonymous type ?
var anoObj = new { name = "testName", email = "testEmail" };
dynamic expandoObj = new System.Dynamic.ExpandoObject();
// Here I'm populating the expandoObj with same property names/types in anonymoustype(anoObj)
// Now, how to convert this ExpandoObject to anonymoustype ?
var newObj = (typeof(anoObj)expandoObj); // This doesn't work
Added Later
// This is my entity
public class Customer
{
#region Public Properties
[ColumnAttribute(Name = "IdColumn")]
public string Id { get; set; }
[ColumnAttribute(Name = "NameColumn")]
public string Name { get; set; }
[ColumnAttribute(Name = "AddressColumn")]
public string Address { get; set; }
[ColumnAttribute(Name = "EmailColumn")]
public string Email { get; set; }
[ColumnAttribute(Name = "MobileColumn")]
public string Mobile { get; set; }
#endregion
}
// -------------------------------------------------------------------------------------
public class LookupService<TEntitySource>
{
public LookupService ()
{
}
public LookupShowable<TEntitySource, TSelection> Select<TSelection>(Expression<Func<TEntitySource, TSelection>> expression)
{
var lookupShowable = new LookupShowable<TEntitySource, TSelection>();
return lookupShowable;
}
}
public class LookupShowable<TEntitySource,TSelection>
{
public LookupShowable()
{
}
public LookupExecutable<TEntitySource, TSelection, TShow> Show<TShow>(Expression<Func<TEntitySource, TShow>> expression)
{
var lookupExecutable = new LookupExecutable<TEntitySource,TSelection,TShow>();
return lookupExecutable;
}
}
public class LookupExecutable<TEntitySource, TSelection, TShow>
{
public TSelection Execute()
{
// Here I want to create a new instance of TSelection and populate values from database and return it.
}
}
//--------------------------------------------------------------------------------------
// This is How I want to call this from front end...
var lookupService = new LookupService<Customer>();
var lookupSelection = lookupService.Select(C => new { C.Id, C.Name, C.Mobile }).Show(C => new { C.Id, C.Name}).Execute();
string sID = lookupSelection.Id;
string sName = lookupSelection.Name;
string sMobile = lookupSelection.Mobile;
Dont think about this middle part.. Purpose of it is another one...
My problem is in Execute() method in LookupExecutable class. I dont know how to create a new instance of TSelection type and assign values to it. This TSelection type is always an anonymous type..

EDIT: I think this question is a prime example of the XY problem. The correct solution doesn't need to concern itself with ExpandoObject or anonymous types, and it would be most likely wrong if it did.
You're looking at it the wrong way. You don't need to create an instance of an anonymous object, you need to invoke the code that is passed to you in an expression (which may or may not be creating an anonymous object).
If you can create an instance of TEntitySource, then that's simple: Compile() the Expression that you got in Select() and then invoke it for each instance of TEntitySource.
If you can't create TEntitySource, you could still do it by rewriting the Expression (using ExpressionVisitor), so that its input is not TEntitySource, but some type you have. But that would require some work from you.
Original answer:
No, that won't work. That's simply not how casting or anonymous types work in C#.
You can't cast between any two types and expect it to work. Either the object you're casting needs to be the type you're casting to, or one of the two types needs to specify a matching cast operator.
The fact that the target type is an anonymous type doesn't change anything (except that you can't even try to cast to an anonymous type directly, because you can't name it; the way you're using typeof() is wrong).
The fact that the source type is dynamic changes things a bit. But only in that the search for the cast operator is done at runtime, not at compile time, and you can even create the cast operator at runtime (see DynamicObject.TryCast()). But that's it, it doesn't add any “magical” cast operators.
The only way I can imagine something like this working would be if you used a variant of “cast by example” and reflection:
public T Convert<T>(ExpandoObject source, T example)
where T : class
{
IDictionary<string, object> dict = source;
var ctor = example.GetType().GetConstructors().Single();
var parameters = ctor.GetParameters();
var parameterValues = parameters.Select(p => dict[p.Name]).ToArray();
return (T)ctor.Invoke(parameterValues);
}
You could then use it something like this:
var expando = new ExpandoObject();
dynamic dynamicExpando = expando;
dynamicExpando.Foo = "SomeString";
dynamicExpando.Bar = 156;
var result = Convert(expando, new { Foo = "", Bar = 1 });
Note that you can't actually invoke Convert() dynamically (by passing it dynamicExpando), because that would mean it would return dynamic too.

Use JavaScriptSerializer to convert the ExpandoObject to any Type as follows:
.....
dynamic myExpandoObject = new ExpandoObject();
var result = ConvertDynamic<myType>(myExpandoObject);
.....
public T ConvertDynamic<T>(IDictionary<string, object> dictionary)
{
var jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
var obj = jsSerializer.ConvertToType<T>(dictionary);
return obj;
}
This should do the job.

here you have an object made from an ExpandoObject
var anoObj = new { name = "testName", email = "testEmail" };
dynamic expandoObj = new System.Dynamic.ExpandoObject();
object newObj = expandoObj;
But beware, dynamic objects are very very expensive in resource matters, and what you are asking for does not seem to have any sense. A good aproach for what you are asking in the comments supposing you have to deal with dynamic objects and you want to do something with them:
dynamic expando = new System.Dynamic.ExpandoObject();
var myObj = new Dictionary<string, object>();
myObj["myProperty"] = expando.myProperty;
Any dynamyc object is easily casted to a <string, object> typed Dicionary.
Hope that helps!

Related

C# Array of anonymous class inside another anonymous class

I deserialize a JSon string that holds an object with an array of subobjects.
The current working solution looks like this:
var definition = new { systems = new subclass[0] };
var ret = JsonConvert.DeserializeAnonymousType(source, definition);
public class subclass
{
public long id;
}
Is there a way to replace the subclass with another anonymous one?
I tried using the following, but only get a compiler error:
var definition = new { constellations = new{ id=0L }[0] };
I wonder if you could do:
var definition = new { systems = MakeEmptyArrayFrom(new { id = 0L}) };
...
static T[] MakeEmptyArrayFrom<T>(T value) => new T[0];
note: if that works, it will probably also work even if you use something like:
static T[] MakeNullArrayFrom<T>(T value) => null;
as I imagine the library is more interested in the Type than the value.

Create properties dynamically

So I have an object with lots of properties, PropertyNameYear1, PropertyNameYear2, PropertyNameYear3...for 20 years. these properties could potentially grow with time, so in the future I might have to add PropertyNameYear21 and so on.
I'm trying to get these properties, both their name and value, without specifying each and every one, since theoretically i can have tens of them. I can do it using LINQ and Object Initializer, but then I have to specify each property twice:
new {
PropertyNameYear1 = f => f.PropertyNameYear1,
PropertyNameYear2 = f => f.PropertyNameYear2,
...
};
How can I, using LINQ (and Refelction?), get all these properties (and only these, assuming there are other properties named differently than PropertyNameYearX) into a new/another object and return that object?
This is a pseudo-code of what I'm looking for:
public ReturnType GetSomeObjectWithSpecificProperties(int ID){
var list = SomeObjectRepository.Where(f => f.ID == ID);
var props = list.GetType().GetProperties().ToList();
var SomePropObjectList = props.Where(f => f.Name.Contains("PropertyNameYear")).ToList();
var listToReturn = SomePropObjectList.Select(f => new {
f.Name = f.GetValue(list)
}).ToList();
return listToReturn;
}
I want to pipe in and say you should rethink your approach.
Instead of having:
public class NotGood
{
public int PropertyNameYear1{ get; set; }
//repeat 20 times...
public int PropertyNameYear21{ get; set; }
}
...consider:
public class Better
{
public List<int> PropertyNameYears{ get; } = new List<int>();
}
It's one line of code and it will scale much better. Plus, you eliminate all the clumsy, reflection-based parsing.
EDIT: As I mentioned in the comments, sometimes the proper approach to clean code is discussing bad code with the author vs. adapting your code to fit the problem they caused, but if there's no way around it, here's an approach that requires four lines of code:
var obj = new
{
SomeNormalProp = "foo",
ThisIsSilly1 = 1,
ThisIsSilly2 = 2,
ThisIsSilly3 = 3,
ThisIsSilly4 = 4
};
dynamic barfObj = new ExpandoObject();
foreach (var prop in obj.GetType().GetProperties())
if (prop.Name.StartsWith("ThisIsSilly"))
//add property dynamically
((IDictionary<string, object>)barfObj).Add(prop.Name, prop.GetValue(obj));
//now barfObj is exactly what you want.
var sampleVal = barfObj.ThisIsSilly1;
var json = JsonConvert.SerializeObject(barfObj);
Or if you're a real masochist, you have Reflection.Emit:
How to dynamically create a class in C#?
You can make use of ExpandoObject to dynamically add Properties from your source class object. Assuming the source class is ClassWithMayProperties:
public object GetObject(ClassWithManyPropererties obj)
{
var props = obj.GetType().GetProperties().Where(p => p.Name.Contains("PropertyNameYear")).ToList();
dynamic returnObject = new ExpandoObject() as IDictionary<string, Object>;
foreach (var property in props)
{
returnObject.Add(property.Name, property.GetValue(obj));
}
return returnObject;
}
Then you can directly get the value of property you want or cast the ExpandoObject in IDictionary and check for the property name as key.
var dynObject = GetObject(obj);
var d = dynObject.PropertyNameYear1

LINQ: use Expression inside Where with anonymous type

Goal: call a method that returns an Expression I can use to chain methods on an anonymous IQueryable.
Example:
var allProducts = from p in ctx.Products;
var customWhere = Product.GiveMeYourQuery();
var productsIWant = allProducts.Where(customWhere);
Console.Writeline("yeaaaaah!");
This is what I've come up with as to now, which, of course, doesn't work:
class MainClass
{
public static void Main(string[] args)
{
var list = new [] {
new { Name = "ciao", Age = 18 },
new { Name = "prova", Age = 28 },
new { Name = "mah", Age = 38 },
new { Name = "boh", Age = 48 }
};
var myAnon = list.Where(x => x.Name.Length > 2).AsQueryable();
var thisthat = new MainClass();
var subset = myAnon.Where(thisthat.Where);
}
public Expression<Func<T, bool>> Where<T>(T anon){
var expr = Expression.Lambda(Expression.Equal(Expression.Constant(anon), Expression.Constant(anon)));
return (Expression<Func<T, bool>>) expr;
}
}
Compiler wisdom:
../Program.cs(24,24): Error CS0407: A method or delegate 'System.Linq.Expressions.Expression LINQInjector.MainClass.Where(anonymous type)' return type does not match delegate `bool System.Func(anonymous type)' return type (CS0407) (LINQInjector)
I feel I'm pretty close, but I cannot really see the path.
Unfortunately I cannot just cast the a' object to a type I create because what the program should output is the SQL (yes, I'm basically building a querybuilder that feeds another tier the queries to execute) and because I'd have to create too many types anyway (each type for each possible chain of joins between tens of tables).
EDIT:
While I appreciate you trying to show me alternatives and workarounds, at this point I think there's none. This is my question: how to inject Expressions into an anonymous type. If this cannot be done just say so.
Since you want to access a property known at compile time of an object outside of the scope in which it's created, you don't want to use an anonymous object. An anonymous object would be appropriate if you're accessing it using lambdas created in the same scope in which the anon object is created, but you don't want to do that. You want to have another method statically access a property of that object. Just give it a name, it'll make everything super easy:
public class Foo
{
public string Name{get;set;}
//...
}
public static Expression<Func<Foo, bool>> NameEquals(string name)
{
return foo => foo.Name == name;
}

How to get values from returned anonymous type

I have a method, which returns abstract class:
public static object CurrentInfo()
{
// some code here
return new
{
URL = "www.mydomain.com",
User = "Jack",
Age = 20
};
}
When I use the method, I obtain an abstract-class result, so I take it into object (or var) type:
object obj = MyClass.CurrentInfo();
//var obj = MyClass.CurrentInfo(); // I also tried that
I cannot access the properties URL, Age and User from the obj object. If I try followings it cause error.
string myUrl = obj.URL // the same form Age and User
Should I CAST it? But to what...? I would like to exclude the way of creating a new STRUCT.
Create a class with those properties so you can properly access them then the return object can be a strongly-typed class rather than an anonymous one. This way you can access the properties of the object.
such as
public class Info
{
public string URL {get; set;}
public string User {get; set;}
public int Age {get; set;}
}
public static Info CurrentInfo()
{
// some code here
return new Info()
{
URL = "www.mydomain.com",
User = "Jack",
Age = 20
};
}
If you want to retain the anonymous type, which as indicated makes it difficult to work with, then here is a solution for dealing with the returned object:
var obj = CurrentInfo();
System.Type type = obj.GetType();
string url = (string)type.GetProperty("URL").GetValue(obj, null);
You could use the type
Tuple<string, string, int>
This is a named class that represents what you're trying to create, and it's already pre-built into the .NET framework so you don't need to create any new classes or structs.
You would write something like
Tuple<string, string, int> obj = Tuple.Create("www.mydomain.com", "Jack", 20);
See the MSDN documentation for a 3-argument tuple: http://msdn.microsoft.com/en-us/library/dd387150(v=vs.110).aspx

C# make a Dictionary of Lambdas

I'm having a trouble defining a Dictionary for quick accessing Lambda Expressions.
Let's suppose we have a well-known class like this:
class Example
{
public string Thing1;
public DateTime Thing2;
public int Thing3;
}
What a want to do is something like this:
var getters = new Dictionary<string, IDontKnowWhatGoesHere>();
getters.Add("Thing1", x => x.Thing1);
getters.Add("Thing3", x => x.Thing3);
Is this possible?
Edit:
This is my use case for this object:
List<Example> array = new List<Example>();
// We actually get this variable set by the user
string sortField = "Thing2";
array.Sort(getters[sortField]);
Many thanks for your help.
You've got a couple of options. If, as in your example, the things you want to get are all the same type (i.e. String), you can do
var getters = new Dictionary<string, Func<Example, String>>();
However, if they're different types, you'll need to use the lowest common subclass, which in most cases will be Object:
var getters = new Dictionary<string, Func<Example, object>>();
Note that you'll then need to cast the return value into your expected type.
Try:
var getters = new Dictionary<string, Func<Example, object>>();
getters.Add("Thing1", x => x.Thing1);
getters.Add("Thing3", x => x.Thing3);
The first generic type parameter of the Func delegate is the type of the input, and the second generic type parameter is the type of the output (use object because you've different output types).
More about Func: Func<T, TResult> Delegate
var getters = new Dictionary<string, Expression<Func<Example, object>>>();
However, string Thing1 should be public.
I really think you are thinking about this in the wrong way. Why use a dictionary at all? If your class definition is correct, then just use a List<Example>.
List<Example> dataList = new List<Example>();
dataList.Add(new Example { Thing1 = "asdf", Thing2 = "qwert", Thing3 = 2 });
Then you can use linq on it.
IEnumerable<Example> sortedByT3 = dataList.OrderBy(x => x.Thing3);
sortedByT3.Last().Thing2 = "hjkl";
You can also use a dynamic order by provided by Marc Gravell's answer:
var sortedByString = dataList.AsQueryable().OrderBy("Thing2");
No need for lambdas, just direct access to the data.
As everyone has said, you need to make the members public. I would suggest you change it to the following:
public class Example
{
public string Thing1 { get; set; }
public string Thing2 { get; set; }
public int Thing3 { get; set; }
}

Categories

Resources