I have a list that contains objects of type IMyClass.
This list contains instances of typed class MyClass<`T>.
I need to take two random objects from the list of the same MyClass type and perform an operation on them.
My code:
var item1 = list[random.Next(list.Count)];
...
var subset = list.OfType<MyClass<item1_T>>().ToList();
var item2 = subset[random.Next(subset.Count)];
What do I have to fill in at the dots to get the type item1_T?
Unfortunately in C# it is no possible to dynamically specify a generic type using the angle brackets notation as you wrote:
var subset = list.OfType<MyClass<item1_T>>().ToList();
Although you certainly could call OfType<> method using reflection:
var list = new List<IMyClass> { ... };
var item1_T = typeof(int);
var subset = (typeof(Enumerable)
.GetMethod(nameof(Enumerable.OfType))
.MakeGenericMethod(typeof(MyClass<>).MakeGenericType(item1_T))
.Invoke(null, new object[]{ list }) as IEnumerable<IMyClass>)
.ToList();
But that would be quite inefficient.
A much faster way would be:
var typeToFind = typeof(MyClass<>).MakeGenericType(item1_T);
var subset = list.Where(item => item != null && item.GetType() == typeToFind).ToList();
If this code is not performance critical, probably it wouldn't matter if you use this solution, otherwise I'd suggest to refactor the code to avoid using reflection.
In IMyClass add this line:
bool AreInterchangable(IMyClass otherInstance);
Implement in MyClass<`T>:
public bool AreInterchangable(IMyClass otherInstance)
{
return otherInstance is IMyClass<T>;
}
Instead of var subset = list.OfType<MyClass<item1_T>>().ToList(); use this:
var subset = list.Where(item => item.AreInterchangable(item1));
Note that I also introduced a generic interface IMyClass<T> which sits between IMyClass and MyClass<T>
Related
Full disclosure, I do not fully understand generics but am hoping the answer to this question will clear things up.
I have an application that allows a user to build a query of their own. The query will leverage the Entity Framework. I would like to return a list of the results whose type is dependent upon what column they queried. In other words i need a method that could have multiple return types. I derive the type using reflection on the column and then would like to pass to this method.
public static T getValues<T>(string ColName, Type type)
{
var result = db.AC_PROPERTY.Select(ColName);
if (type == typeof(string))
{
List<string> list = new List<string>();
//Query and add results to list.
return list;
}
if (type == typeof(double?) || type == typeof(double))
{
List<double> list = new List<double>();
//Query and add results to list.
return list;
}
if (type == typeof(int) || type == typeof(int?))
{
List<int> list = new List<int>();
//Query and add results to list.
return list;
}
if (type == typeof(DateTime))
{
List<DateTime> list = new List<DateTime>();
//Query and add results to list.
return list;
}
}
I am getting an error stating that I cannot implicitly convert List (or the respective type) to T.
Can someone explain this and perhaps walk me through how to accomplish this.
Ask yourself this: How are T and Type type meaningfully different? Why do you need both?
You don't.
Furthermore, while it's technically possible to check for a generic parameter's type, you should not be doing this. It's a code smell. If your method is generic, the method body should be generic as well. This includes not needing to know the exact value of T.
1. Get rid of Type type
public static List<T> getValues<T>(string ColName)
{
//...
}
Notice how this method would be used:
List<DateTime> myDateList = getValues<DateTime>("MyDateTimeColumn");
2. Make the method body generic
public static List<T> getValues<T>(string ColName)
{
List<T> myReturnList = new List<T>();
var selectedColumnValues = db.AC_PROPERTY.Select(ColName);
//Query and add results to list.
return myReturnList;
}
Looks a lot neater, doesn't it? I noticed you omitted the actual creating of the list; so I omitted it too for now.
I could get into the rest of the method body based on some assumptions, but there's a much more relevant consideration here.
Your method seems to be no different from LINQ's Select() method!
So instead of doing this with your custom built getValues<T> method:
List<DateTime> myDateList = getValues<DateTime>("MyDateTimeColumn");
You can use the existing LINQ method:
List<DateTime> myDateList = myDataList.Select(item => item.MyDateTimeProperty).ToList();
(Note: ToList() can be optional but is advisable due to lazy evaluation).
Is there a simpler way to write the following? I.E., without the lambda.
var strings = new[] { "Alabama", "Mississippi", "Louisiana" };
var ordered = strings.OrderBy(x => x);
Seems like it should be possible, since string implements IEquatable<string>.
It's IComparable that matters more thanIEquatable here, but it is possible:
Array.Sort(strings);
This works because strings is already an array. Since you asked for any IEnumerable:
var ary = strings.ToArray();
Array.Sort(ary);
Note the extra variable is also important in this second sample, because Array.Sort() sorts the actual object passed without returning the results, and calling .ToArray() created a new array that was then thrown away. Without the extra variable, you lose your work.
There is a similar sort method on the List<T> object you can use, as well.
You can also make your own extension method for this:
public static class MyExtensions
{
public static IOrderedEnumerable<T> Sort(this IEnumerable<T> items) where T : IComparable
{
return items.OrderBy(i => i);
}
}
And now you could just say:
var ordered = strings.Sort();
For .NET 7 or higher, use Order.
var strings = new[] { "Alabama", "Mississippi", "Louisiana" };
var ordered = strings.Order();
dotnet/runtime#67194
I thought I had a good understanding of the anonymous type, but this small code snippet has left me a little confused:
string[] arr = { "Agnes", "Allan", "Benny" };
var result = arr.Where(a => a.StartsWith("A")).Select(a => a);
// Why can I do the below, if arr is immutable?
result = arr.Where(a => a.EndsWith("n")).Select(a => a);
What I don't understand is why I am allowed to assign a second value to result. I mean isn't the idea of anonymous types being immutable, that they cannot be changed after they have got their initial value?
First, there is no anonymous type involved.
This string[] arr = { "Agnes", "Allan", "Benny" }; is an array creation expression.
result is IEnumerable<string> and in both LINQ statements you are just creating a query.
This is what is going on:
array creation expression
string[] arr = { "Agnes", "Allan", "Benny" };
query arr and returns IEnumerable<string>
var result = arr.Where(a => a.StartsWith("A")).Select(a => a);
assigns results a new query on arr returning IEnumerable<string>
result = arr.Where(a => a.EndsWith("n")).Select(a => a);
As far as, for understanding immutability, think of String also see this article: Immutable types: understand their benefits and use them
You have an anonymous type when you do something like:
var anon = new { X = 5, Y = 6 };
There are some pretty simple rules: you can't express the type of an anonymous type (so often you use var)... there must be a new {... You must give a name to the properties and a value X = 5.
What you are doing is creating an array of string[] using an array initializer. You are even writing it:
string[] arr = ...
And you aren't modifying anything... result is another variable, referencing an IEnumerable<> (a new object you are creating) and then referencing another IEnumerable<> At the end of your code you have 6 objects (a little more, but we will ignore some invisible objects):
The array referenced by arr (and referenced by the two IEnumerable<>)
The second IEnumerable<>, referenced by result, that has a reference to arr
The first IEnumerable<>, not referenced by anyone (the GC will collect it before or later), that has a reference to arr
3x string, all referenced by arr. Note that IEnumerable<> are "lazy", so they don't contain any reference to any string
The result variable is assigned twice, to two different IEnumerable<>. It is nearly always legal to reassign variables (exception are readonly fields). it is clearly legal to do:
string foo = "Foo";
foo = "Bar";
Another useful concept to understand is the difference between type, instance and variable.
Simplifying, type is like a blueprint, it describes what an instance of the type will look like:
class Car
{
public int Doors {get; set;}
public string EngineType { get; set;}
}
The code above describes type. You can make many instances of this type:
Car truck = new Car { Doors = 2, EngineType = "BigEckingEngine" };
Car pickup = new Car { Doors = 5, Engine Type = "4 cylinder" };
etc...
Note how variables truck and pickup house your instances. But variables are just that, they can house any instance of their respective type, so while it does not make much sense you can do this:
Car tmp = truck;
truck = pickup;
pickup = tmp;
The instances themselves has not changed. But the variables now hold different instances.
The instances of this example Car class above are mutable. So you can do this:
pickup.Doors = 99;
Should the type be immutable, you would not be able to do that, but you are still can do variable assigning as in the example with the tmp variable freely, regardless of type being mutable or not, because such assignment do not change instances.
As noted, your example does not contain an anonymous type, but even if it did, it does not involve any kind of mutation you are asking about.
LINQ methods like Where() and Select() don't change the underlying array. It creates a new object. The created result is of type IEnumerable<string>, LINQ just filters the array so if you will iterate over it later, you will just get values that match Where and Select but your arr object will remain unchanged.
It's worth expanding the other answers to show that a CONCRETE resolution of a LINQ query is not the same as a IEnumerable<T> and that neither have anything to do with anonymous type immutability.
If you created the following array of anonymous types:
var arr = new[] { new { Name = "Agnes"}, new { Name = "Allan" }, new { Name = "Benny" }};
arr.GetType().Dump();
var result = arr.Where(a => a.Name.StartsWith("A")).Select(a => a)
result = arr.Where(a => a.Name.EndsWith("n")).Select(a => a);
result.Dump();
in my case,
<>f__AnonymousType0`1[System.String][]
and
"Allan"
are respectively outputted, because result type is actually
System.Linq.Enumerable+WhereSelectArrayIterator`2[
<>f__AnonymousType0`1[System.String],
<>f__AnonymousType0`1[System.String]]
In addition, if I try to resolve the IEnumerable and then re-update the result:
var result = arr.Where(a => a.Name.StartsWith("A")).Select(a => a).ToList();
result = arr.Where(a => a.Name.EndsWith("n")).Select(a => a).ToList();
I once again get an output of
"Allan"
However, in this case my result type has been reevaluated to
System.Collections.Generic.List`1[<>f__AnonymousType0`1[System.String]]
since ToList() is creating a new collection. I can technically add and remove to that collection at will since the collection itself is quite willing to be mutated.
Finally, that does not mean that the underlying anonymous type object is not immutable!
result.First ().Name = "fail";
Will fail, regardless of result being a list with the following error:
Property or indexer 'AnonymousType#1.Name' cannot be assigned to -- it
is read only
precisely because it is immutable.
I have to write a query in a web application using LINQ but I need to change that query into an array list. How can I change the query below to do this?
var resultsQuery =
from result in o["SearchResponse"]["Web"]["Results"].Children()
select new
{
Url = result.Value<string>("Url").ToString(),
Title = result.Value<string>("Title").ToString(),
Content = result.Value<string>("Description").ToString()
};
If you really need to create an ArrayList, you can write new ArrayList(resultsQuery.ToArray()).
However, you should use a List<T> instead, by writing resultsQuery.ToList().
Note that, in both cases, the list will contain objects of anonymous type.
There is a .ToArray() method that'll convert IEnumerable to an Array.
ArrayList doesn't have a constructor or Add(Range) method that takes an IEnumerable. So that leaves two choices:
Use an intermediate collection that does implement ICollection: as both Array and List<T> implement ICollection can be used via the ToArray() or ToList() extension methods from LINQ.
Create an instance of ArrayList and then add each element of the result:
var query = /* LINQ Expression */
var res = new ArrayList();
foreach (var item in query) {
res.Add(item);
}
The former method is simple to do but does mean creating the intermediate data structure (which of the two options has a higher overhead is an interesting question and partly depends on the query so there is no general answer). The latter is more code and does involve growing the ArrayList incrementally (so more memory for the GC, as would be the case for an intermediate Array or List<T>).
If you just need this in one place you can just do the code inline, if you need to do it in multiple places create your own extension method over IEnumerable<T>:
public static class MyExtensions {
public static ArrayList ToArrayList<T>(this IEnumerable<T> input) {
var col = input as ICollection;
if (col != null) {
return new ArrayList(col);
}
var res = new ArrayList();
foreach (var item in input) {
res.Add(item);
}
return res;
}
}
I am not accustomed to use Var implicitly typed variable. Anyone can let me know the advantage to use such variable?
Annonymous types:
var person = new { Name = "John", Surname = "Doe" };
One thing is that it's a short hand for long types...Such as:
List<Dictionary<string, object>> myList = getList();
Can be simplified to:
var myList = getList();
Under normal use, 'var' is entirely optional and equivalent to manually specifying the type. See here.
However, the 'var' keyword is needed for anonymous types, which I've normally used in conjunction with LINQ.
I specifically find it much easier to read this:
foreach(var dbitem in context.usp_GetUserAndAccountData())
{
txtUserName.Text = dbitem.UserName;
// ...
}
Than this:
foreach(ISingleResult<usp_GetUserAndAccountDataResult> dbitem in context.usp_GetUserAndAccountData())
{
txtUserName.Text = dbitem.UserName;
// ...
}
For me, regardless of what I explicitly define dbitem, I'll still do the same actions; so var here is priceless!
And the beauty of it all is that IntelliSense will still list you all the members of the expected type on the other end (such as UserName in my example).
Better code readability. Especially used with constructors and long type name:
var anArray = new String[3];
var iStream = new InputStream(...);
var dict = new Dictionary<string, int>();
Just be mindful that using var is not always what it seems (though mostly is). An example is this:
dataList is a DataList control on a webform
foreach (var item in dataList.Items)
{
// item is of type System.Object
}
foreach (DataListItem item in dataList.Items)
{
// item is of type DataListItem
}
I believe that it was created for the purpose of anonymous types (ala Kugels example):
var person = new { Name = "John", Surname = "Doe" };
However since I discovered it I have to admit I have found it quite useful in day-to-day use when dealing with longer type names, for example:
var aaa = new Dictionary<string, List<ReallyLongTypeName>>();
// vs
Dictionary<string, List<ReallyLongTypeName>> aaa = new Dictionary<string, List<ReallyLongTypeName>>();
Another side effect is that type names can change (or be replaced with other types), but code that uses var wont' break, for example:
var item = this.GetItem();
this.Name = item.Name;
this.Age = item.Age;
As long as the return value from GetItem always has a property Name and a property Age (which are compatible with the properties on this) then GetItems can return an entirely different object and the above code will still compile. (But be careful - existing compiled assemblies can't use the same trick!)
Apart from the other answers, to me a real advantage is when dealing with external code, to decouple the variable type from the actual method signature.
Consider this interface:
public interface IFoo
{
List<Foo> GetSomething();
}
And say you have two lines of code:
List<Foo> foos = fooRepo.GetSomething();
var foos2 = fooRepo.GetSomething();
Same result for above two lines. (List<Foo> returned).
Now if changed the interface:
public interface IFoo
{
Dictionary<bool,Foo> GetSomething();
}
The first line would now throw a compiler error, the second would not:
List<Foo> foos = fooRepo.GetSomething(); // error - can't convert from Dictionary<bool,Foo> to List<Foo>
var foos2 = fooRepo.GetSomething(); // works!
This is really handy when working with repositories/other projects where interface contracts/method signatures can change.
Yes you still have to recompile the classes, but you don't have to go back and change all the code that referenced the old return type.