Nested generics with IDictionary and IEnumerable - c#

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.

Related

Covariance/Conversion issue with Generics

Consider the code:
using System.Collections.Generic;
namespace TestingTypes
{
class Program
{
static void Main(string[] args)
{
var strings = new List<string>();
INeedToPassThisMethodAListOfObjects(strings as List<object>);
}
static void INeedToPassThisMethodAListOfObjects(List<object> objects) { }
}
}
1>------ Build started: Project: TestingTypes, Configuration: Debug Any CPU ------
1>c:\users\[censored]\TestingTypes\Program.cs(9,41,9,64): error CS0039: Cannot convert
type 'System.Collections.Generic.List<string>' to
'System.Collections.Generic.List<object>' via a reference conversion, boxing
conversion, unboxing conversion, wrapping conversion, or null type conversion
You might say that a List<string> is a List<object>, since a string is an object and C# 4 is supposed to support covariance in generic types.
Why does the compiler say it can't convert the type?
How do I pass "strings" to the method?
Interfaces can be variant; classes cannot. See here for the explanation.
Your code will work if you pass the strings collection uncasted and change the declaration to be
static void INeedToPassThisMethodAListOfObjects(IEnumerable<object> objects) { }
However, that depends on whether you need a List within this function.
You're getting the error because a List<string> is not a List<object>.
You can call list.Add(new TextBox()) on List<object> but, obviously, the same call doesn't work on List<string>.
C# Generics only allow for Covariance if the generic type is immutable (which is my the cast from List to IEnumerable works).
If you need to pass the list to a method, you could try passing
listOfStrings.Cast<object>();
On the downside, if you use that solution, any modifications made to the list inside the method call will not be reflected in the original list (because the call to Cast creates a new list).
If you have control of the method INeedToPassThisMethodAListOfObjects and that method only needs to iterate over the collection rather than modify it, you can change the parameter type to be IEnumerable<object> in which case you'd simply be able to pass your List<string> without any issues.
You have to convert the strings to objects. Theres a nice LINQ method to do so.
var strings = new List<string>();
INeedToPassThisMethodAListOfObjects(strings.Cast<object>());
Edit
According to your own link,
In C#, variance is supported in the following scenarios:
Covariance in arrays (since C# 1.0)
Covariance and contravariance in delegates, also known as “method group variance” (since C# 2.0)
Variance for generic type parameters in interfaces and delegates (since C# 4.0)
So IEnumerable would accept List

Function Parameter type determined at runtime?

Is it in anyway possible ( preferably without using any third party libs), to create a function whose type is determined at runtime in C#?
e.g
public static void myfunc(var x)
{
System.Windows.Forms.MessageBox.Show(x); //just an example
}
NOTE: I want the runtime to determine the type of the parameter and do not want to later cast the parameter to another type, as would be necessary if I use generics. e.g I don't want:
myfunc<T>(T x)
// and then :
MessageBox.Show((string)m);
UPDATE:
I am actually making a function parser for my programming language, which translates to C# code. In my language, I wanted the parameter types to be determined at runtime always. I was looking for some good C# feature for easy translation.
e.g
in my language syntax:
function msg << x
MessageBox.Show x
end
needed to be translated to something that didn't ask for a type at compile time, but would need one at runtime.
e.g
public static void msg(var x)
{
System.Windows.Forms.MessageBox.Show(x);
}
The keyword introduced for runtime binding in C# 4 is dynamic.
public static void myfunc(dynamic x)
This allows you to make assumptions about x that are unchecked at compile time but will fail at runtime if those assumptions prove invalid.
public static void MakeTheDuckQuack(dynamic duck)
{
Console.WriteLine(duck.Quack());
}
The assumption made here is that the parameter will have a method named Quack that accepts no arguments and returns a value that can then be used as the argument to Console.WriteLine. If any of those assumptions are invalid, you will get a runtime failure.
Given classes defined as
class Duck
{
public string Quack()
{
return "Quack!";
}
}
class FakeDuck
{
public string Quack()
{
return "Moo!";
}
}
And method calls
MakeTheDuckQuack(new Duck());
MakeTheDuckQuack(new FakeDuck());
MakeTheDuckQuack(42);
The first two succeed, as runtime binding succeeds, and the third results in an exception, as System.Int32 does not have a method named Quack.
Generally speaking, you would want to avoid this if possible, as you're essentially stipulating that an argument fulfill an interface of some sort without strictly defining it. If you are working in an interop scenario, then perhaps this is what you have to do. If you are working with types that you control, then you would be better served trying to achieve compile time safety via interfaces and/or base classes. You can even use different strategies (such as the Adapter Pattern) to make types you do not control (or cannot change) conform to a given interface.
If you need to know the type... then you need to know the type. You can't have your cake and eat it too.
First off, the cast in your example is unnecessary as all objects implement ToString(). Instead of telling us what you think you need, tell us what problem you are trying to solve. There is almost certainly a solution either via generics or the use of the dynamic keyword (though dynamic is rarely needed), but we need more info. If you add more I'll update this answer.
You could use a type of object or, if you don't know how many items are available, you could use a params object array, i.e. params object[] cParams.

IEnumerable.ToArray<T>() vs. IEnumerable.Cast<T>().ToArray()

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.

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;
}

What is the "< >" syntax within C#

I have been learning about the basics of C# but haven't come across a good explanation of what this is:
var l = new List<string>();
I don't know what the <string> is doing or if it's the List that is doing the magic. I have also seen objects been thrown within the < > tags.
Can someone explain this to me with examples, please?
That is the generic syntax for C#.
The basic concept is that it allows you to use a Type placeholder and substitute the actual real type in at compile time.
For example, the old way:
ArrayList foos = new Arraylist();
foos.Add("Test");
worked by making ArrayList store a list of System.Objects (The base type for all things .NET).
So, when adding or retrieving an object from the list, The CLR would have to cast it to object, basically what really happens is this:
foos.Add("Test" as System.Object);
string s = foos[1] as String.
This causes a performance penalty from the casting, and its also unsafe because I can do this:
ArrayList listOfStrings = new ArrayList();
listOfStrings.Add(1);
listOfStrings.Add("Test");
This will compile just fine, even though I put an integer in listOfStrings.
Generics changed all of this, now using Generics I can declare what Type my collection expects:
List<int> listOfIntegers = new List<int>();
List<String> listOfStrings = new List<String>();
listOfIntegers.add(1);
// Compile time error.
listOfIntegers.add("test");
This provides compile-time type safety, as well as avoids expensive casting operations.
The way you leverage this is pretty simple, though there are some advanced edge cases. The basic concept is to make your class type agnostic by using a type placeholder, for example, if I wanted to create a generic "Add Two Things" class.
public class Adder<T>
{
public T AddTwoThings(T t1, T t2)
{
return t1 + t2;
}
}
Adder<String> stringAdder = new Adder<String>();
Console.Writeline(stringAdder.AddTwoThings("Test,"123"));
Adder<int> intAdder = new Adder<int>();
Console.Writeline(intAdder.AddTwoThings(2,2));
For a much more detailed explanation of generics, I can't recommend enough the book CLR via C#.
It's generics - it's a form of type parameterisation. In your example, it's making l refer to a list of strings - the list will only ever contain strings: the compiler treats it (pretty much) as if everywhere that the API docs mention "T" it actually says "string". So, you can only add strings to it, and if you use the indexer you don't need to cast to string, etc.
To be honest, giving generics detailed coverage on an online forum is pretty much impossible. (In C# in Depth, I take nearly 50 pages talking about generics.) However, armed with the name of the feature, you should be in a much better position to find out more. The MSDN "Introduction to C# Generics" is probably a good starting point.
Asking specific questions about generics on SO is likely to yield good results - I just don't think it can really be covered properly in one question/answer.
This is .NET Generics. The type within the < > denotes the type of element contained in the list.
with ArrayList you'd have to cast the elements inside...
int x = (int)myArrayList[4];
with List you can avoid that step because the compiler already knows the type.
int x = myList[4];
Generics are available in .NET 2.0 and later.
Those are generics. You are making a List that only contains strings. You could also say
List<int>
and get a list that only contains ints.
Generics is a huge topic, too big for a single answer here.
Those are known as Generics (specifically List is a generic class).
Reading from MSDN
Generics (C# Programming Guide)
An Introduction to C# Generics
Generics in the .NET Framework
This is generics in action. A regular List stores items of type Object. This requires casting between types. This also will allow you to store any kind of item in one instance of a list. When you are iterating through items in that list you cannot be sure that they are all of a certain type (at least not without casting each item). For instance lets say you create a list like this:
List listOfStrings = new List();
Nothing prevents someone from doing something like this:
listOfStrings.add(6); //Not a string
A generic list would allow you to specify a strongly-typed list.
List<string> listOfStrings = new List<string>();
listOfStrings.add("my name"); //OK
listofStrings.add(6); //Throws a compiler error
There is a more thorough examples on here Generics
< > is for generics. In your specific example, it means that the List is a List of strings, not say a list of ints.
Generics are used to allow a type to be, well, generic. It's used ALOT in Collections to allow them to take different types so that they can function much like a normal array and still catch invalid types being assigned at compile time. Basically it allows a class to say "I need to be associated with some specific type T, but I don't want to hard code exactly what that type is, and let the user select it.". A simple array for instance might look something like:
public class MyArray<T> {
private T[] _list;
public MyArray() : this.MyArray(10);
public MyArray(int capacity)
{ _list = new T[capacity]; }
T this[int index] {
get { return _list[index]; }
set { _list[index] = value; }
}
}
Here, we have a private list of type T that is accessed by using our class like a normal array. We don't care what type it is, it doesn't matter to our code. But anyone using the class could use it as, say MyArray<string> to create a list of strings, while someone else might use it as MyArray<bool> and create a list of flags.

Categories

Resources