tags:

views:

109

answers:

3

I want to do something like this:

public static TResult MyCast<TSource, TResult>(TSource item)
{
    return (TResult)item;
}

Without restrictions on TSource or TResult and avoiding unnecessary boxing if possible. Edit: I want to stress out, that I want a simple casting of types, not elaborate type conversion here. It would be perfectly ok to fail at casting, say string to int.

Is there any sane way to do this using CLR 2.0?

Edit: this is a simplified version, so it's pretty useless, yes. But consider casting generic collections, such as this:

public static Dictionary<string, TResult> CastValues<TSource, TResult>(this Dictionary<string, TSource> dictionary)

After some discussions with my co-workers, it seems like there's no simple way to implement such a feature (if at all possible), so I'm stuck with code bloat of several very simple methods for different situations (i.e. up- and downcast of reference types and casting of some value types) :(

Too bad I can't use .NET 4.0 with all it's dynamic et al goodness.

+6  A: 

How would
x = MyCast<SourceType, ResultType>(y)
be any more useful than
x = (ResultType)y ?

Henk Holterman
usually you do it as MyCast<TOutput>(object input) because you want to use it in generic invocation with reflection for a dynamic cast. I don't see the reason for such a method as well.
Femaref
This is a simplified example. My actual need is for method like this: public static Dictionary<string, TResult> CastValues<TSource, TResult>(this Dictionary<string, TSource> dictionary)
13xforever
@13xforever: How about using the Cast and OfType extension methods?
simendsjo
@simendsjo: that would only work for some cases and where they're applicable, I obviously in no need to write some silly wrapper to call them.
13xforever
+2  A: 

This is straightforward when TSource and TResult are both reference types.

If one or the other are value types, how do you want it to work? Value types can't inherit from each other, so it's not a matter of doing an up- or down-cast. You might expect numeric conversions between, say, int and double, but you'd have to code these yourself: .NET doesn't treat them as typecasts. And conversion between, say, DateTime and string involves more intelligence (what format? which culture? etc.).

If you're just handling reference types then this method can be a one-liner. If you want to handle value types as well then you'll need to write special case code for the various combinations.

Edit: Convert.ChangeType does a reasonable job at encapsulating the various conversions between value types. However you mentioned you're keen not to introduce boxing: Convert.ChangeType isn't generic and it takes an object.

Tim Robinson
I'm interested only in explicit casts that you typically perform during development (in other words, I don't want it to be intelligent enough to do custom converts between types).And even considering reference types, I cannot think of a single method that could perform up- and downcasts at the same time (well, not in CLR prior to 4.0).All in all, that's why I'm asking.Right now I have custom generic methods for all types that I'm using ATM. They're all very simple and do the same exact thing. That's just... unsettling.
13xforever
"explicit casts that you typically perform during development" - these are actually rules implemented by the C# compiler. The syntax is the same for all casts, but the compiler knows how to convert between the various numeric types; it generates different IL for different pairs of types. Inside your `MyCast` method you'll need to reimplement these rules yourself.
Tim Robinson
@Tim Robinson: yes, I know. It's just that DLR prototype introduced in .NET 4.0 was at some point a separate project that run on top of the CLR, so I thought that maybe there's a reasonably easy way to do a runtime casting. :D
13xforever
Hmm -- `Convert.ChangeType`, but I guess that's not ideal either.
Tim Robinson
Thanks for `Convert.ChangeType`. Even if it's not that much useful in this particular case, it's the most useful piece of knowledge here nonetheless.
13xforever
A: 

I think that the problem you are trying to solve is the same as the problem that you cannot cast a collection of one type to a collection of another type. eg

class Obj1
{}
class Obj2:Obj1
{}
List<Obj2> srcList = GetList();
List<Obj1> castedList=(List<Obj2>) srcList;//this line wont compile

I have not done much at actually looking at the CLR code However on the asuumption that it is like C++ what you would have here is actually different values stored in the collection. In other words srcList would contain a list of pointers to object 2's interface in castedList you would have a pointer to the the interface of the object 1's within object 2.

In order to resolve this you would need to have your casting function iterate through each of the items within the collection. However in order to be able to iterate through the items the list would have to implement some sort of enumeration interface. So the enumeration interface would need to be a constraint on the casting function.

So the answer would therefore be no.

However if you were prepared to implement this with restrictions on the in types you could have:

static class ListCast<TSource,TResult,TItemType>
  where TSource:IEnumerable<TItemType>
  where TResult:IList<TItemType>,new()
{
  static TResult Cast(TSource list)
  {
    TResult castedList=newTResult();
    foreach(TtemType item in list)
    {
       castedList.Add(TItemType)item);
    }

     return castedList;
   }
}

developer
That's ok. I'm not looking into complex type-conversion solutions. I want a runtime type casting, that's all. And at this point I'm pretty sure there isn't any simple solution.
13xforever