Passing IEnumerable Data from LINQ as a Parameter to a Method

Possible duplicate:
How to pass an anonymous type to a method?

I have the following LINQ statement, the output of which must be processed in a different way:

 var data = from lines in File.ReadAllLines(TrainingDataFile) .Skip(ContainsHeader ? 1 : 0) let f = lines.Split(new[] { FieldSeparator }).ToList<String>() let target = f[TargetVariablePositionZeroBased] select new { F=f, T=target }; 

What should be the data type of the parameter in the method that will receive this data?

+8
c # linq
source share
3 answers

You cannot easily skip anonymous types. You can create a class, or since your data has only two properties, use Tuple :

 select new Tuple<List<string>, string> (f, target); 

If I have the correct data types, then the parameter data type will be:

 IEnumerable<Tuple<List<string>, string>> 

and you must reference F and T using the Tuple properties Item1 and Item2 .

+3
source share

You cannot return anonymous data types from a method. You can define a class and return an object of this class from the request and pass it to the target method.

 public class SomeClass { public string F {get; set;} public string T {get; set;} } var data = from lines in File.ReadAllLines(TrainingDataFile) .Skip(ContainsHeader ? 1 : 0) let f = lines.Split(new[] { FieldSeparator }).ToList<String>() let target = f[TargetVariablePositionZeroBased] select new SomeClass { F=f, T=target }; 

You can pass the result of the IEnumerable<SomeClass> request to the method as a parameter.

 public void MethodToCall(IEnumerable<SomeClass> someClass) { } 

To call the method, passing the result of the request ( IEnumerable<SomeClass> ), which is stored in data in this code example

 MethodToCall(data); 
+8
source share

1) To pass the result of the request, make your function common, which will do:

 var data = from lines in File.ReadAllLines(TrainingDataFile) .Skip(ContainsHeader ? 1 : 0) let f = lines.Split(new[] { FieldSeparator }).ToList<String>() let target = f[TargetVariablePositionZeroBased] select new { F=f, T=target }; SomeMethod(data); public void SomeMethod<T>(IEnumerable<T> enumerable) { // ^^choose the return type.. } 

Simple If the processing inside the method is so simple that it will be done. But you cannot access the F and T properties inside the method.

For this:

2) You can use the "cast by example" trick shown here by Eric. To quote it:

We use method type inference and local variable type inference to tell the compiler "these two things are of the same type." This allows you to export an anonymous type as an object and return it to an anonymous type.

... the trick only works if the example and source objects were created in code in the same assembly; two "identical" anonymous types in two different assemblies are not combined to be the same type.

 SomeMethod(data); public void SomeMethod(IEnumerable<object> enumerable) { var template = new { F = new List<string>(), T = string.Empty }; foreach (var item in enumerable) { var anonymousType = item.CastToTypeOf(template); //print string.Join(", ", anonymousType.F) + " - " + anonymousType.T //compiles //or whatever } } //a more generic name perhaps is 'CastToTypeOf' as an extension method public static T CastToTypeOf<T>(this object source, T example) where T : class { return (T)source; } 

The SomeMethod here is that SomeMethod now specifically designed for your anonymous type, since you specify a specific type inside the method, so it’s best not to make the function common (although you can) and give a suitable name for the function.

3) If the function is only for your unique type now, I would be better off to have them all wrapped in one method and not pass at all - no hassle! :)

4) Or you can delegate the action that needs to be performed for your anonymous type. Thus, the signature of the method will look like this:

 SomeMethod(data, d => print string.Join(", ", dF) + " - " + dT); public void SomeMethod<T>(IEnumerable<T> enumerable, Action<T> actor) { foreach (var item in enumerable) actor(item); } 

If that matters, you can have a Func delegate, also having another type argument.

5) Rely on fuzzy reflection to get properties from your anonymous type otherwise.

6) Use the dynamic keyword in the method argument, and now you have dynamic typing. Both of the above do not give you the benefits of static input.

7) You would be better off having a separate class that contains F and T And this is the best. But ask yourself, do they together represent something as an entity ?

8) If not, just pass an IEnumerable<Tuple> or IDictionary depending on what matters.


It all depends on what / how you want to achieve using the method. Personally, I would go for approach 2 in the hobby project (for fun), but in production code 3, 4, 7, 8 depending on the context.

+3
source share

All Articles