Come as guests, stay as family.

I ♥ 4MGHC


Hướng dẫn sử dụng diễn đàn Với mong muốn có một Website hỏi đáp chất lượng 4MGHC đã ra đời. Đây là cộng đồng hỏi đáp dành cho lập trình viên, sinh viên, các bạn ưu thích lập trình... Việt Nam. Huy vọng các bậc tiền bối, các bằng hữu gần xa chung tay chia sẽ, giúp đỡ, giải đáp các thắc mắc trên Website. Cùng nhau củng cố, đóng góp cho sự nghiệp phát triển thông tin, công nghệ của đất nước.
Trong diễn đàn bạn có thể
  1. Hỏi đáp trong diễn đàn
  2. Đánh giá và like bài post
Đăng ký

Số người đang xem trên diễn đàn: 1056
1
  1. Tân thế giới
    Posts:
    784320
    Vote:
    2
    Like:
    3
    How to pass anonymous types as parameters?
    Image
    Image
    Users online on this topic: 1
    How can I pass anonymous types as parameters to other functions? Consider this example:

    Code: Select all
    var query = from employee in employees select new { Name = employee.Name, Id = employee.Id };
    LogEmployees(query);


    variable query here doesn't have strong type. How should I define my LogEmployees function to accept it?

    Code: Select all
    public void LogEmployees (? list)
    {
    foreach (? item in list)
    {

    }

    }


    In other words, what should I use instead of ? marks.
    Image 8
    Image
  2. Bài viết cùng chủ đề:How to pass anonymous types as parameters?
  3. Ký Túc Xá
    Posts:
    2533979
    Vote:
    21
    Like:
    2
    Image
    Image
    I think you should make a class for this anonymous type. That'd be the most sensible thing to do in my opinion. But if you really don't want to, you could use dynamics:

    Code: Select all
    public void LogEmployees (IEnumerable<dynamic> list)
    {
    foreach (dynamic item in list)
    {
    string name = item.Name;
    int id = item.Id;
    }
    }


    Note that this is not strongly typed, so if, for example, Name changes to EmployeeName, you won't know there's a problem until runtime.
    Image 20
    Image
    Image
    Image
  4. Ký Túc Xá
    Posts:
    2533979
    Vote:
    21
    Like:
    2
    Image
    Image
    You can do it like this:

    Code: Select all
    public void LogEmployees<T>(List<T> list) // Or IEnumerable<T> list
    {
    foreach (T item in list)
    {

    }
    }


    ... but you won't get to do much with each item. You could call ToString, but you won't be able to use (say) Name and Id directly.
    Image 10
    Image
    Image
  5. Ký Túc Xá
    Posts:
    2533979
    Vote:
    21
    Like:
    2
    Image
    Image
    Unfortunately, what you're trying to do is impossible. Under the hood, the query variable is typed to be an IEnumerable of an anonymous type. Anonymous type names cannot be represented in user code hence there is no way to make them an input parameter to a function.

    Your best bet is to create a type and use that as the return from the query and then pass it into the function. For example,

    Code: Select all
    struct Data {
    public string ColumnName;
    }

    var query = (from name in some.Table
    select new Data { ColumnName = name });
    MethodOp(query);
    ...
    MethodOp(IEnumerable<Data> enumerable);


    In this case though, you are only selecting a single field, so it may be easier to just select the field directly. This will cause the query to be typed as an IEnumerable of the field type. In this case, column name.

    Code: Select all
    var query = (from name in some.Table select name); // IEnumerable<string>
    Image 10
    Image
    Image
  6. Ký Túc Xá
    Posts:
    2533979
    Vote:
    21
    Like:
    2
    Image
    Image
    You can't pass an anonymous type to a non generic function, unless the parameter type is object.

    Code: Select all
    public void LogEmployees (object obj)
    {
    var list = obj as IEnumerable();
    if (list == null)
    return;

    foreach (var item in list)
    {

    }
    }


    Anonymous types are intended for short term usage within a method.

    From MSDN - Anonymous Types:

    Quote: Select all


    You cannot declare a field, a property, an event, or the return type of a method as having an anonymous type. Similarly, you cannot declare a formal parameter of a method, property, constructor, or indexer as having an anonymous type. To pass an anonymous type, or a collection that contains anonymous types, as an argument to a method, you can declare the parameter as type object. However, doing this defeats the purpose of strong typing.



    (emphasis mine)

    Update

    You can use generics to achieve what you want:

    Code: Select all
    public void LogEmployees<T>(IEnumerable<T> list)
    {
    foreach (T item in list)
    {

    }
    }
    Image 7
    Image
    Image
  7. Ký Túc Xá
    Posts:
    2533979
    Vote:
    21
    Like:
    2
    Image
    Image
    Normally, you do this with generics, for example:

    Code: Select all
    MapEntToObj<T>(IQueryable<T> query) {...}


    The compiler should then infer the T when you call MapEntToObj(query). Not quite sure what you want to do inside the method, so I can't tell whether this is useful... the problem is that inside MapEntToObj you still can't name the T - you can either:

    call other generic methods with T
    use reflection on T to do things

    but other than that, it is quite hard to manipulate anonymous types - not least because they are immutable ;-p

    Another trick (when extracting data) is to also pass a selector - i.e. something like:

    Code: Select all
    Foo<TSource, TValue>(IEnumerable<TSource> source,
    Func<TSource,string> name) {
    foreach(TSource item in source) Console.WriteLine(name(item));
    }
    ...
    Foo(query, x=>x.Title);
    Image 4
    Image
    Image
  8. Ký Túc Xá
    Posts:
    2533979
    Vote:
    21
    Like:
    2
    Image
    Image
    You can use generics with the following trick (casting to anonymous type):

    Code: Select all
    public void LogEmployees<T>(IEnumerable<T> list)
    {
    foreach (T item in list)
    {
    var typedItem = Cast(item, new { Name = "", Id = 0 });
    // now you can use typedItem.Name, etc.
    }
    }

    static T Cast<T>(object obj, T type)
    {
    return (T)obj;
    }
    Image 3
    Image
    Image
  9. Ký Túc Xá
    Posts:
    2533979
    Vote:
    21
    Like:
    2
    Image
    Image
    I've seen (and somewhat ashamed to say, done) a hack to be able to pass an anonymous type from a query to a method.

    It's called "casting by example".

    Here's an article that came up when I googled "casting by example c#"

    http://tomasp.net/articles/cannot-return-anonymous-type-from-method.aspx

    It might get the job done in a tight stop, but I wasn't too proud of it.
    Image 2
    Image
    Image
  10. Ký Túc Xá
    Posts:
    2533979
    Vote:
    21
    Like:
    2
    Image
    Image
    If you know, that your results implements a certain interface you could use the interface as datatype:

    Code: Select all
    public void LogEmployees<T>(IEnumerable<T> list)
    {
    foreach (T item in list)
    {

    }
    }
    Image 0
    Image
    Image
  11. Ký Túc Xá
    Posts:
    2533979
    Vote:
    21
    Like:
    2
    Image
    Image
    I would use IEnumerable<object> as type for the argument. However not a great gain for the unavoidable explicit cast.
    Cheers
    Image 0
    Image
    Image
1