IEnumerable.ToArray<T>() vs. IEnumerable.Cast<T>().ToArray() - c#

When trying to obtain an array of objects from an IEnumerable collection of objects (cast differently than the array I want), I know I can first cast the source collection to the proper type, and then obtain an array from that, but the method ToArray<T>() gives me the impression that it can handle both of those operations in one step. From my experience, though, I have never been able to find a case where the ToArray<T>() method works for any T except the original source's T (which, in my mind, makes ToArray<T>() silly, since it does the same thing that the non-generic ToArray() already does).
So my question is, am I missing the point of the ToArray<T>() method, and I'm trying to make it do something it was never intended for, or is there something silly I'm missing with regard to the method, and what I'm trying to do does generally follow its intent?
Here is a concrete example to illustrate my issue:
public interface IFoo { }
public class Foo : IFoo { }
static void Main(string[] args)
{
// Suppose a list of Foos was created
List<Foo> src = new List<Foo>();
// I would be safe obtaining an array of IFoos from that list, but
// This is not supported (although intellisense shows the method is there, the compiler balks):
// IFoo[] results = src.ToArray<IFoo>();
// Whereas this works just fine:
IFoo[] results = src.Cast<IFoo>().ToArray();
}

The reason ToArray<T>() is generic is so that it can operate on any IEnumerable<T>, not so that you can supply a different T:
public static T[] ToArray<T>(this IEnumerable<T> self) { ... }
You should never need to provide the T yourself. If you did, as in your example, the method would expect to receive, for example, an IEnumerable<IFoo>, which you are not supplying.
FYI, there is no "non-generic ToArray()". The compiler is inferring the T generic argument based on the type of enumerable you call ToArray() on.

Related

How do you convert a SortedList into a SortedList<>

Due to the existing framework I am using, a method call is returning a SortedList object. Because I wrote the other side of this call I know that it is in fact a SortedList. While I can continue to work with the SortedList, using the generic would convey my meaning better. So, how do you change the non-generic SortedList into an appropriately typed generic SortedList?
The background on this is that the call is a remote procedure call using the SoapFormatter. The SoapFormatter does not implement generics (Thank you, Microsoft). I cannot change the formatter since some non-.Net programs also use other method calls against the service.
I would like my proxy call to look like the following:
public SortedList<string, long> GetList(string parameter)
{
return _service.GetList(parameter);
}
Where the interface for the GetList call is as follows due to the SoapFormatter requirements:
public SortedList GetList(string parameter);
You can't directly convert, as a SortedList is not actually a SortedList<T>, even if it only contains elements of type T.
In order to turn this into your appropriate type, you'd need to create a SortedList<T> and add all of the elements into it.
A conversion function for your usage:
static SortedList<TKey,TValue> StronglyType<TKey,TValue>(SortedList list) {
var retval = new SortedList<TKey,TValue>(list.Count);
for(int i=0; i<list.Count; i++)
retval.Add((TKey)list.GetKey(i), (TValue)list.GetByIndex(i));
return retval;
}
The equivalent foreach(DictionaryEntry entry in list) approach is slightly slower due to the implicit cast to unbox the DictionaryEntry (you always need the casts to TKey/TValue).
Ballpark performance overhead: On my years old machine here, this function takes 100ms to convert a 1000 lists with 1000 entries each.

How am i allowed to pass a method to List.Sort()?

i am calling Sort on a List:
List<Stuff> list = new List<Stuff>();
list.Sort(StuffSortByName);
with the StuffSortByName declaration of:
private static int StuffSortByName(Stuff x, Stuff y)
{
...
}
What surprises me is that my code compiles and works. It's surprising that no overload of Sort takes a method:
Sort()
Sort(Comparison<T>)
Sort(IComparer<T>)
Sort(Int32, Int32, IComparer<T>)
So i was fortunate, as i didn't want to have to create a whole object, that implements IComparer, just to sort stuff. But for the life of me i don't understand while it compiles.
And now i want to duplicate that magic. i want to sort a ListView. But you don't sort a listivew, you give a listview an IComparer through it's ListViewItemSorter property:
listView1.ListViewItemSorter = [IComparer]
And, again, i don't want to write a whole object, i just want to pass a local method (and ideally a non-static one):
listView1.ListViewItemSorter = SortListView;
private static int SortListView(Object x, Object y)
{
....
}
Now of course this doesn't compile because it makes no sense. But then the earlier syntax shouldn't compile either - but it does.
So it gives me hope that i can have the same confusing syntax here.
How was i allowed to pass a method as a sort comparer in the first case, but not in the second case?
To answer your first question, the reason the method name can be passed is because Comparison<T> is a delegate type, meaning it is a type representing a method signature. See MSDN for details.
In your case, you should either create an IComparer object or have your Stuff object implement IComparable or IComparable<T> (if possible).
I think you simply use this overload. which uses Comparison
From link:
If comparison is provided, the elements of the List(Of T) are sorted
using the method represented by the delegate
EDIT
What about ListView, as you noticed too, it implements IComparer and not Comparison, so you can not just pass a delegate to it.

Nested generics with IDictionary and IEnumerable

In a generic C# class for an internal reusable library, I'd like to pass a reference to "something that maps to a list of other things". The data types of what is passed in there are not supposed to be known by the library. Also, the way they are stored should not be known either, i.e. what is today a list that is held in memory, might later be a database table that is read from on demand.
So I thought I'd write this library class:
class GenericClass<T, U>
{
public void Foo(IDictionary<T, IEnumerable<U>> bar)
{
// do something
}
}
This compiles, but trying to pass in concrete implementations does not:
class UsingClass
{
public static void Main(string[] args)
{
var c = new GenericClass<string, string>();
c.Foo(new Dictionary<string, List<string>>());
}
}
I'm getting the following two syntax errors:
Filename.cs(46,13): error CS1502: The best overloaded method match for 'GenericClass<string,string>.Foo(System.Collections.Generic.IDictionary<string,System.Collections.Generic.IEnumerable<string>>)' has some invalid arguments
Filename.cs(46,19): error CS1503: Argument 1: cannot convert from 'System.Collections.Generic.Dictionary<string,System.Collections.Generic.List<string>>' to 'System.Collections.Generic.IDictionary<string,System.Collections.Generic.IEnumerable<string>>'
Replacing the IEnumerable on the declaration of Foo() with List fixes it, but that's of course not quite what I want.
Is this really not supported by C# (4.0) or am I just missing something obvious? What workaround would you suggest? (I'm sure this has been talked about before a lot, so links to great descriptions are fine, too.)
Yes, I should be able to write my own helper classes for that, but why do I have to?
Yes, this is really not supported. Imagine your Foo method looked like this:
public void Foo(IDictionary<T, IEnumerable<U>> bar)
{
T key = GetKeyFromSomewhere();
bar[key] = new U[10]; // Create an array
}
That looks okay, doesn't it? We can convert from U[] to IEnumerable<U>.
It's not so good from the caller's point of view though - suddenly we've got a string[] reference value in the dictionary, when all the values are meant to be List<string> references! Bang goes type safety.
You can rewrite the method as:
public void Foo<TValue>(IDictionary<T, TValue> bar)
where TValue : IEnumerable<U>
That will let you get values out of the dictionary and convert them to IEnumerable<U> implicitly... but you'd only be able to put exactly the right type of value into the dictionary, and you can't build that just from a U value.
As of version 4, C# supports generic variance in restricted circumstances. So for example, this works in C# 4 (when targeting .NET 4) but previously wouldn't:
List<string> strings = new List<string>();
IEnumerable<object> objects = strings;
For a lot more on generic variance, see Eric Lippert's blog series on the topic. Be prepared for your brain to explode periodically.

Why can't I cast from a List<MyClass> to List<object>?

I have a List of objects, which are of my type QuoteHeader and I want to pass this list as a list of objects to a method which is able to accept a List<object>.
My line of code reads...
Tools.MyMethod((List<object>)MyListOfQuoteHeaders);
But I get the following error at design time...
Cannot convert type 'System.Collections.Generic.List<MyNameSpace.QuoteHeader>'
to 'System.Collections.Generic.List<object>'
Do I need to do anything to my class to allow this? I thought that all classes inherit from object so I can't understand why this wouldn't work?
The reason this is not legal is because it is not safe. Suppose it were legal:
List<Giraffe> giraffes = new List<Giraffe>();
List<Animal> animals = giraffes; // this is not legal; suppose it were.
animals.Add(new Tiger()); // it is always legal to put a tiger in a list of animals
But "animals" is actually a list of giraffes; you can't put a tiger in a list of giraffes.
In C# this is, unfortunately, legal with arrays of reference type:
Giraffe[] giraffes = new Giraffe[10];
Animal[] animals = giraffes; // legal! But dangerous because...
animals[0] = new Tiger(); // ...this fails at runtime!
In C# 4 this is legal on IEnumerable but not IList:
List<Giraffe> giraffes = new List<Giraffe>();
IEnumerable<Animal> animals = giraffes; // Legal in C# 4
foreach(Animal animal in animals) { } // Every giraffe is an animal, so this is safe
It is safe because IEnumerable<T> does not expose any method that takes in a T.
To solve your problem you can:
Create a new list of objects out of the old list.
Make the method take an object[] rather than a List<object>, and use unsafe array covariance.
Make the method generic, so it takes a List<T>
Make the method take IEnumerable
Make the method take IEnumerable<object> and use C# 4.
You can't cast List<OneType> to List<OtherType> as it is actually the instances of the list you want to cast, as well as the List itself.
there is an extension method which will allow you to do this (MSDN reference):
IEnumerable<Object> myNewEnumerable = myEnumerable.Cast<Object>();
This method will attempt to cast each instance of the list of one type to the other type and add them to a new enumerable. it will throw an exception if any instance can't be cast.
As far as the system is concerned the two types for your lists are just different types, so it is like saying:
A objectOfTypeA;
B objectOfTypeB = (B) objectofTypeA;
To be able to do the cast there would have to be an implicit or explicit conversion between the types available, which there isn't (unless you provided one, which you might be able to do).
you expect it to work because List<object> will always be able to hold any type in another list, but when you think about it in those terms you can see why it doesn't.
I'm sure there is a more technically competent answer, but that is the gist of it I think.
you might be interested in reading Eric Lippert's series on Covariance and Contravariance as this may be helpful to you.
This question may also be useful
List<MyClass> x = someList.Select(f => (MyClass)f).ToList();
I'm presuming that you mean that the lists are of types which inherit from each other or can otherwise be cast from one type to another - in that case, try this:
Tools.MyMethod(MyListOfQuoteHeaders.Cast<OtherType>());
Thanks for the many responses.
I'll explain what I wanted to do and what I've come up with as a solution.
I needed a method that I could call by passing in a List of objects of any type and then output that list to XML. Also passed to the method would be a string which would be a system file structure path location which points to the location the XML file would be saved to. As I have an ever growing number of classes and types, I wanted to avoid writing multiple methods to cater for each type of class. I'm not sure if I've even gone about this the right way, but it's a lightweight solution to my problem and works. If there are any issues with it, or if anyone has any comments please feel free...
So... my method now looks like this...
public static Enums.Status WriteListToXML<T>(string outputPath, List<T> inboundList)
{
try
{
XmlSerializer xmlSerializer = new XmlSerializer(inboundList.GetType());
using (StreamWriter streamWriter = System.IO.File.CreateText(outputPath))
{
xmlSerializer.Serialize(streamWriter, inboundList);
}
return Enums.Status.Success;
}
catch (Exception ex)
{
return Enums.Status.Failure;
}
}
... and my calling line reads...
WriteListToXML<QuoteHeader>(#"C:\XMLDocuments\output\QuoteHeaders.xml", quoteHeadersList);
Like I said, it may not be the tidiest solution, but it works well in my scenario.
The problem is that at Compile time, the compiler emits 2 separate classes, 1 that represents List<MyClass> and one that represents List<Object>. They are essentially 2 separate types. That's how Generic types work, in .Net at least.
Assuming this is .Net, you could do
MyListOfQuoteHeaders.Cast<Object>()
which basically does
var objects = new List<Object>();
foreach(var item in MyListOfQuoteHeaders)
{
objects.Add((object)item);
}
return objects;

How to do a static cast in C#?

Given a couple types like this:
interface I {}
class C : I {}
How can I do a static type cast? By this I mean: how can I change its type in a way that gets checked at compile time?
In C++ you can do static_cast<I*>(c). In C# the best I can do is create a temporary variable of the alternate type and try to assign it:
var c = new C();
I i = c; // statically checked
But this prevents fluent programming. I have to create a new variable just to do the type check. So I've settled on something like this:
class C : I
{
public I I { get { return this; } }
}
Now I can statically convert C to I by just calling c.I.
Is there a better way to do this in C#?
(In case anyone's wondering why I want to do this, it's because I use explicit interface implementations, and calling one of those from within another member function requires a cast to the interface type first, otherwise the compiler can't find the method.)
UPDATE
Another option I came up with is an object extension:
public static class ObjectExtensions
{
[DebuggerStepThrough]
public static T StaticTo<T>(this T o)
{
return o;
}
}
So ((I)c).Doit() could also be c.StaticTo<I>().Doit(). Hmm...probably will still stick with the simple cast. Figured I'd post this other option anyway.
Simply cast it:
(I)c
Edit Example:
var c = new C();
((I)c).MethodOnI();
Write an extension method that uses the trick you mentioned in your UPDATE:
public static class ObjectExtensions
{
public static T StaticCast<T>(this T o) => o;
}
To use:
things.StaticCast<IEnumerable>().GetEnumerator();
If things is, e.g., IEnumerable<object>, this compiles. If things is object, it fails.
// Compiles (because IEnumerable<char> is known at compiletime
// to be IEnumerable too).
"adsf".StaticCast<IEnumerable>().GetEnumerator();
// error CS1929: 'object' does not contain a definition for 'StaticCast'
// and the best extension method overload
// 'ObjectExtensions.StaticCast<IEnumerable>(IEnumerable)'
// requires a receiver of type 'IEnumerable'
new object().StaticCast<IEnumerable>().GetEnumerator();
Why Use a Static Cast?
One common practice during refactoring is to go ahead and make your changes and then verify that your changes have not caused any regressions. You can detect regressions in various ways and at various stages. For example, some types of refactoring may result in API changes/breakage and require refactoring other parts of the codebase.
If one part of your code expects to receive a type (ClassA) that should be known at compiletime to implement an interface (IInterfaceA) and that code wants to access interface members directly, it may have to cast down to the interface type to, e.g., access explicitly implemented interface members. If, after refactoring, ClassA no longer implements IIterfaceA, you get different types of errors depending on how you casted down to the interface:
C-style cast: ((IInterfaceA)MethodReturningClassA()).Act(); would suddenly become a runtime cast and throw a runtime error.
Assigning to an explicitly-typed variable: IInterfaceA a = MethodReturningClassA(); a.Act(); would raise a compiletime error.
Using the static_cast<T>-like extension method: MethodReturningClassA().StaticCast<IInterfaceA>().Act(); would raise a compiletime error.
If you expected your cast to be a downcast and to be verifiable at compiletime, then you should use a casting method that forces compiletime verification. This makes the intentions of the code’s original developer to write typesafe code clear. And writing typesafe code has the benefit of being more verifiable at compiletime. By doing a little bit of work to clarify your intention to opt into typesafety to both other developers, yourself, and the compiler, you magically get the compiler’s help in verifying your code and can catch repercussions of refactoring earlier (at compiletime) than later (such as a runtime crash if your code didn’t happen to have full test coverage).
var c = new C();
I i = c; // statically checked
equals to
I i = new C();
If you're really just looking for a way to see if an object implements a specific type, you should use as.
I i = whatever as i;
if (i == null) // It wasn't
Otherwise, you just cast it. (There aren't really multiple types of casting in .NET like there are in C++ -- unless you get deeper than most people need to, but then it's more about WeakReference and such things.)
I i = (I)c;
If you're just looking for a convenient way to turn anything implementing I into an I, then you could use an extension method or something similar.
public static I ToI(this I #this)
{
return #this;
}

Categories

Resources