Assign a function delegate that returns an anonymous type to a variable - c#

The code below is valid:
IEnumerable<SomeThing> things = ...;
// map type SomeThing to a new anonymous type, resulting in a strongly typed
// sequence based on an anon type
var newList = things.Select(item =>
{
return new
{
ID = item.ID,
DateUpdatedOrCreated = ((DateTime)(item.DateUpdated ??
item.DateCreated)).ToShortDateString(),
Total = item.Part1 + item.Part2
};
});
newList now appears in Visual Studio as IEnumerable<'a> and is strongly typed with the anonymous type created in the function. That is so cool.
What I can't seem to do is figure out a way to assign just the lambda expression (and not the enumeration) to an implicitly typed variable. Even though the compiler has no problem with the anonymous type in the context above, if I try (say)
var func = (SomeThing item)=> {
return new { ... };
};
I get the error "Cannot assign lambda expression to implicitly-typed local variable". This seems a strange compiler limitation; unless I am missing something, the types are just as non-ambiguous in the 2nd example as they are in the first first: both type parameters are well defined.
Is there any way to do this? Since it's an anonymous type, of course, I don't have any way to use a type to assign it explicitly, so it seems I'd be stuck with making a class for the output type if not.
Update
Shortly after going about my merry way with Jon Skeet's answer, I found a similar dilemma instantiating classes. In case it's not obvious, the same trick can be used to create strongly typed classes using inferred anonymous types.
class Processor<T,U>
{
public Processor(Func<T,U> func) {
}
}
// func is a delegate with anon return type created using method in answer below
var instance = new Processor(func); // does not compile! Requires type arguments!
cannot be created directly, but can be created in much the same way as the trick below:
public static Processor<T,U> Create<T,U>(Func<T,U> func) {
return new Processor<T,U>(func);
}
var instance = Processor.Create(func); // all good

You can do it via type inference:
var func = BuildFunc((SomeThing item) => {
return new { ... };
});
...
static Func<TSource, TResult> BuildFunc<TSource, TResult>(
Func<TSource, TResult> function) {
return function;
}
Note that BuildFunc doesn't really do anything - it just provides the method call needed to get the compiler to do type inference for the generic type arguments for Func<,> - it adds the information that you're interested in Func<,>, basically - that's information which can't be specified as part of a variable declaration, without also specifying the type arguments.

Related

Build a compiled delegate corresponding to Enumerable.Cast<T>?

This is very tricky and I'm stuck at the step calling the generic method (MethodInfo) which is returned by another MethodCallExpression (by using MakeGenericMethod) right inside the expression tree context.
Technically the compiled delegate I want looks like this:
Func<IEnumerable, Type, IEnumerable> cast;
So instead of using items.Cast<T>() I can call my compiled delegate like cast(items, typeof(T)).
If using reflection every time calling cast, it would be easy but here I would like to build a compiled delegate based on Expression tree. Here is my code:
public static class EnumerableExtensions {
static readonly Func<IEnumerable, IEnumerable<object>> _enumerableCast = Enumerable.Cast<object>;
static readonly Lazy<MethodInfo> _enumerableCastDefLazy = new Lazy<MethodInfo>(() => _enumerableCast.Method.GetGenericMethodDefinition());
static MethodInfo _enumerableCastDef => _enumerableCastDefLazy.Value;
static Func<Type[], MethodInfo> _makeGenericMethod = _enumerableCastDef.MakeGenericMethod;
static readonly Lazy<Func<IEnumerable, Type, IEnumerable>> _enumerableCompiledCastLazy =
new Lazy<Func<IEnumerable, Type, IEnumerable>>(() => {
var itemsParam = Expression.Parameter(typeof(IEnumerable));
var castTypeParam = Expression.Parameter(typeof(Type));
var castTypeParams = Expression.NewArrayInit(typeof(Type), castTypeParam);
var castMethod = Expression.Call(Expression.Constant(_enumerableCastDef),_makeGenericMethod.Method, castTypeParams);
//here we need to call on castMethod (a static method)
//but the Expression.Call requires a MethodInfo, not an Expression returning MethodInfo
var cast = Expression.Call(..., itemsParam);//<--------- I'm stuck here
return Expression.Lambda<Func<IEnumerable, Type, IEnumerable>>(cast, itemsParam, castTypeParam).Compile();
});
public static Func<IEnumerable, Type, IEnumerable> EnumerableCompiledCast => _enumerableCompiledCastLazy.Value;
public static IEnumerable Cast(this IEnumerable items, Type type){
return EnumerableCompiledCast(items, type);
}
}
So as you can see it's really a dead stuck, never encountered such an issue like this before. I know I can work-around it by invoking the castMethod (as a MethodCallExpression). That way I need to obtain the Invoke method of MethodInfo and use Expression.Call to call that method on the instance castMethod. But wait, if so we still use Method.Invoke as we use Reflection to write code usually without compiling it? I really believe in some hidden magic of Expression.Call which does something different (better and faster) than the MethodInfo.Invoke.
What you're trying to do is completely pointless, and very unlike Enumerable.Cast, which actually does something useful.
Let's take a look at the latter's definition:
IEnumerable<T> Cast<T>(this IEnumerable source);
This takes an untyped IEnumerable and returns a typed IEnumerable<T> based on the generic argument given to the function. You can then use the elements inside the enumerable with the proper type directly, including value types.
Now let's look at your function definition:
IEnumerable Cast(this IEnumerable items, Type type);
This takes an untyped enumerable and returns also an untyped enumerable. What it does inside isn't important, because even if it worked as you want, what you get out of this is still an enumerable of plain objects, so to use these values you still need to cast these things correctly (and unbox the boxed value types). You achieved nothing at all, you already had such a collection -- the thing you passed to your function in the first place.
Even if you make the cast work using a cache of compiled expressions, one per type, which isn't hard to do, the output is still cast back to object by your very return type.

Explicit cast in c# generic

The non-generic version of CastRangeAndAdd works fine. If I skip the (object)
var castedList = list.Select(e => (NewType)e).ToList();
then there is a compile error. If I use the (object) then there is an exception "type TypeHintExcel can not be converted to TypeHint" though the cast operator is there. Any idea? (TypeHint and TypeHintExcel are not related so as I understand the "as keyword" can not be used.)
public static explicit operator TypeHint(TypeHintExcel p)
{
var result = new TypeHint()
{
Id = p.Id,
Hint = p.Hint,
ExternalType = p.ExternalType,
AlienType = p.AlienType,
Weight = p.Weight
};
return result;
}
public static class DbSetExtensions
{
public static void CastRangeAndAdd<OldType, NewType>
(this System.Data.Entity.DbSet<NewType> dbCollection,
List<OldType> list)
where NewType : class
{
var castedList = list.Select(e => (NewType)(object)e).ToList();
dbCollection.AddRange(castedList);
}
}
You can't write a generic method to do this. The explicit conversion operation needs to be bound at compile time, but when that method is compiled it has no idea what the source and destination types are, so it can't possibly be bound to your custom conversion operator.
c# is not as flexible as c++
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/differences-between-cpp-templates-and-csharp-generics
C++ allows code that might not be valid for all type parameters in the template, which is then checked for the specific type used as the type parameter. C# requires code in a class to be written in such a way that it will work with any type that satisfies the constraints. For example, in C++ it is possible to write a function that uses the arithmetic operators + and - on objects of the type parameter, which will produce an error at the time of instantiation of the template with a type that does not support these operators. C# disallows this; the only language constructs allowed are those that can be deduced from the constraints.

Create list of generic object at runtime

I have object of some type known at runtime and I read and deserialize this object from database. It works. Now I would like to add it to some list:
private static List<T> generateList<T>()
{
List<T> lst = new List<T>();
return lst;
}
private void readObjects(System.Type objType)
{
var methodInfo = typeof(My.Serializator).GetMethod("DeserializeDb");
var genericMethod = methodInfo.MakeGenericMethod(objType1);
List<curType> currentList= generateList<curType>();
// ...read stream from database and convert it to object
while (_rs.Read())
{
var _objItem = genericMethod.Invoke(null, new[] { _streamedData });
currentList.Add(_objItem);
}
}
It won't work. The error is:
curType is a variable but is used like a type.
If I change list to:
List<object> currentList = new List<object>();
it will work. But can i do this with generics(T) instead of object type?
You can easly create type of list you want via Activator, then cast to IList and use it:
private IList readObjects(System.Type objType)
{
var listType = typeof(List<>).MakeGenericType(curType);
var list = (IList)Activator.CreateInstance(listType);
// ...
while (_rs.Read())
{
// ...
list.Add(_objItem);
}
}
list will be instance of List<YorActualType>.
Update
When you declaring your method with generic arguments, it assumes you provide type info during compile time. Otherwise you need to use reflection.
Since you providing type info in run time (curType can hold any type info), compiler does not know what exactly type will be used, and you cannot declare your method to return something concrete. Only abstractions allowed.
Let's me show it on slightly insane but demonstrative example:
var types = new [] { typeof(int), typeof(string) };
var rand = new Random();
var list = readObjects(types[rand.Next(0,2)];
Until the very last moment even you will not know what exactly type of list will be created. Compiler does not know too. Compiler will never know what exactly type should be used if you not provide him with you types. When you use Type it only tells compiler that some regular parameter with type Type will be passed into the method in run time. There is no data to infer a type during compile time. That data can be passed only via generic type parameters.
So, there is several ways you can follow:
Provide exact types you need at compile time
private List<T> readObjects<T>()
{
var objType = typeof(T);
var list = new List<T>();
// rest of code....
}
Use reflection and base types
private IList readObjects(Type objType)
{
// rest of code with Activator and so on
}
And later usage depends on your needs.
If you know what type you going to use, simply convert:
var list = (IList<MyType>)readObjects(typeof(myType));
But I guess in that case better use way #1 with generic argument.
Otherwise you going to use reflection. Or some base classes, interfaces and so on. It depends on what exactly task you going to solve.
P.S. You can read more about generic types on MSDN.

How to return Anonymous Type while using Linq [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
LINQ to SQL: Return anonymous type?
Do any one know how to return an anonymous type. I am using Linq where i need to return the following code
private <What's the return type to be provided here> SampleLinq(Int32 Num)
{
var query = (from dept in obj.DeptTable where dept.Id == Num select new { dept.DeptName, dept.DeptId });
return (query)
}
Sorry to say but you cannot return anonymous type out side the scope of method.
This is the alternate way to get anonmous type
// Method that returns anonymous type as object
object ReturnAnonymous()
{
return new { City="Prague", Name="Tomas" };
}
// Application entry-point
void Main()
{
// Get instance of anonymous type with 'City' and 'Name' properties
object o = ReturnAnonymous();
// This call to 'Cast' method converts first parameter (object) to the
// same type as the type of second parameter - which is in this case
// anonymous type with 'City' and 'Name' properties
var typed = Cast(o, new { City="", Name="" });
Console.WriteLine("Name={0}, City={1}", typed.Name, typed.City);
}
// Cast method - thanks to type inference when calling methods it
// is possible to cast object to type without knowing the type name
T Cast<T>(object obj, T type)
{
return (T)obj;
}
you can use it only for types in one assembly (two anonymous types from two different assemblies will be internally compiled to two different types that can't be converted using this trick).
Return Dynamic type:
public static dynamic getCustomer()
{
.....
var x = from c in customers
select new {Fname = c.FirstName};
return x;
}
static void Main(string[] args)
{
dynamic x = getCustomer();
Console.WriteLine(Enumerable.First(x).Fname);
Console.ReadKey();
}
you can't do that. that is why it is called anonymous. It doesn't have a name. But you always can cast it to object
Well, you can't actually do that, but here's a hack on this.
private object SampleLinq(Int32 Num)
{
return (from dept in obj.DeptTable where dept.Id == Num select new { dept.DeptName, dept.DeptId });
}
You can't return an Anonymous Type from a method.
You can create a simple Class to wrap the Anonymous Type, but you still need a Class (or cast to object).
Keep in mind, though, that if you cast to object there's no way to cast back. You'll need reflection to read any data.
The answers you see from the hack is a lot of work just to get an anonymous type through a method boundary. You shouldn't be doing this. If you need to pass something back from a method, you should be passing concrete types.
It depends what you looking to do with the return vale.
If your going to bind it in the UI
you can just rerun
IEnumerable or IQueryable.
If your going to use reflection on the return value just return type object
If your using c# 4.0 you can return a
dynamic type
If your using EF or Linq to SQL to further join a query comprised of your anonymous type you
can make a concrete class instead and
use the concrete placeholder
technique. For more details on this
technique I can give some assistance.
As others have mentioned though, you should really question whether returning an anonymous type form a method is the best way to solve the problem at hand. In general there is usually a better more pattern based approach that may require a bit more coding up front but may resulting in a more elegant design. This being said, I do believe there are legitimate cases such as with data binding where returning anonymous type instances can be perfectly acceptable.
UPDATE:
Just an interested tidbit I wanted to share in case those reading are not aware. Anonymous types are unique per their property names and types so lets say you have method A and method B in in both you create an anonymous type that has a single string typed property called Name by doing something like be code below.
public object A()
{
return new { Name = "Cid" }
}
public object B()
{
return new { Name = "Galuf" }
}
public void Test()
{
System.Diagnostics.Trace.Assert(A().GetType() == B().GetType());
}
Now even though this type is defined in two separate places the compiler only creates only creates a single shared type because they both have the same set of properties as defined by the property types and property names. In this respect the properties can be thought of as sort of a signature for the anonymous type. Using this knowledge there are different techniques that can be used for introspection into anonymous type instances that have been cast to object or deferred using the dynamic keyword. There are also nifty ways to work with anonymous types by using generic methods just as Linq does with methods in the static Enumerable and Queryable classes. This way you can do things like create a new instance of any given anonymous type and without using reflection. The trick is though that you have to use an instance of the anonymous type to pass to methods in order to have the type be inferred by the generic method. If anybody is interested in these topics further as they apply to the original posters question, leave a comment and I can try to clarify some of these techniques.

Define an anonymous structure as a parameter in a method

Can I define an object-structure as a parameter to a method in the parameter declaration without having to create a type?
I am inspired by LINQ to SQL queries, where you are able to return a subset of your query-results in the form of a new object:
var query = from t in dc.Table select new { Foo = t.column };
What you're describing isn't possible. In the case of your Linq to Sql query, the C# compiler creates an anonymous type with a single property named Foo with the same type as t.column. Type inferencing is then used and the variable "query" is actually strongly typed to this anonymous type (which is what gives you intellisense goodness on this variable).
Using "var" as a parameter type isn't possible because the type of the parameter can't be inferred, it requires the calling expression to decide on the actual type of the parameter.
The best that you could do would be to use generics and iterate through properties:
public static void Print<T>(T obj)
{
Type type = typeof(T);
PropertyInfo[] properties = type.GetProperties();
foreach(PropertyInfo pi in properties)
{
Console.WriteLine(pi.Name + ": " + pi.GetValue(obj, null));
}
}
which gives you a "rudimentary" ability to use anonymous types (or any type for that matter) as a parameter.
Nope, you cannot declare an anonymous type as an input parameter, and you cannot return it, unless you return it as an object. See this blog post for a hacky workaround, if you want, but that's really still just boxing and unboxing the type back and forth, so it's not actually better than just treating it as an object.
How useful is a parameter to a function that you can't use directly? Function parameters should help document the function.

Categories

Resources