Casting List<x> to List<y> - c#

The following code works:
List<JsonStock> stock = new List<JsonStock>();
foreach(tblStock item in repository.Single(id).tblStocks)
stock.Add((JsonStock) item);
So naturally you'd think that this code would work too:
List<JsonStock> stock = repository.Single(id).tblStocks.Cast<JsonStock>().ToList()
But I get the error Invalid cast operation - does anybody know why that might happen?
UPDATE
tblStocks is a list of LINQ to SQL object, tblStock.
JsonStock is a simplified version of the tblStock class and gets returned to a webpage as a JSON object.
The following operator was built to do the casting:
public partial class tblStock{
public static explicit operator JsonStock(tblStock stock){
JsonStock item = new JsonStock
{
boxes = stock.boxes,
boxtype = stock.tblBoxType.name,
boxtype_id = stock.boxtype_id,
grade = stock.grade,
packrate = stock.packrate,
weight = stock.weight
};
return item;
}
}

Cast is used to change a non-generic collection into a generic one, i.e. it performs an unboxing operation. It can't be used the way you want.
When you have a look at the implementation of Cast and the CastIterator it uses, you see, that it takes an object and casts it to the specified type:
foreach (object current in source)
{
yield return (TResult)current;
}
This only works if current really is a TResult. No custom conversions are applied in this case.
This is the default behavior, you can test it yourself:
double d = 0.0;
object tmp = d;
int i = (int)tmp; // throws the same exception you are getting
What you want is best achieved with a simple Select if tblStocks is a generic enumerable:
List<JsonStock> stock = repository.Single(id).tblStocks
.Select(x => (JsonStock)x).ToList();
Or, if tblStocks is a non-generic enumerable, you need to combine Cast and Select:
List<JsonStock> stock = repository.Single(id).tblStocks.Cast<tblStock>()
.Select(x => (JsonStock)x).ToList();
This will first unbox the objects in tblStocks to their real type (tblStock) and then cast it to the type you want (JsonStocks).

implicit and explicit conversion operators are ignored by Cast. In your case that means that
public static explicit operator JsonStock(tblStock stock)
is ignored by Cast they are however not ignored in the foreach case

Instead of using Cast, consider using OfType. In Cast, if the item you are processing isn't the destired type, you will get the InvalidCastException. With OfType, it will trap for invalid cast and only return items that actually are the type that you are looking for.
List<JsonStock> stock = repository.Single(id).tblStocks.OfType<JsonStock>().ToList()
If you return empty lists however, I would suspect that your tblStocks actually is not returning JsonStocks and you are trying to project some other type (tblStock?) into a DTO (JsonStock). If the later is the case, you need to use Select to project into the new type from the underlying type.
List<JsonStock> stock = repository.Single(id).tblStocks
.Select(stock => new JsonStock
{
Id = stock.Id,
Val1 = stock.Val1,
Val2 = stock.Val2,
...
}
.ToList();

Ahhh, the wonders of explicit operator overloads.
So to fix your problem you might want to call a Select beforehand.
List<JsonStock> stock = repository.Single(id).tblStocks.Select(x => (JsonStock)x).ToList()
However i'd say that this operator overload is something you should get rid of. Consider replacing it with a copy constructor like implementation
class JsonStock
{
public JsonStock(tblStock other)
{
// copy values here
}
}

tblStocks.Cast<JsonStock>() performs a cast.
(JsonStock) item performs a cast or applies a custom-defined conversion.
Since tblStock is a LINQ to SQL class and JsonStock is a custom class created by you, none is a subtype of the other. Thus, you cannot cast between the two.
To fix this, you can use the Select clause of LINQ and manually convert the elements:
List<JsonStock> stock = repository.Single(id).tblStocks
.Select(item => (JsonStock) item).ToList();

Related

dynamic.ToString() unexpected behaviour

I'm wondering how does this code work:
dynamic dynaString = 2;
string b = dynaString.ToString();
When this one is not working:
var list = new List<dynamic>();
var liststring = new List<string>();
liststring = list.Select(x => x.ToString()).ToList();
I know I can add Cast<string> after Select statement but that does not explain that behaviour. Why does ToString() on dynamic element work different when called on dynamic variable declared in code than on dynamic variable taken from list in LINQ.
I've looked into method signature of Select and it's:
My guess is that x here is a dynamic variable, so it should behave just like dynaString, but it's not. Intellisense is suggesting me that this x.ToString() returns string:
Anyone got experience with dynamics in C# and can explain me that?
I've also tried this code:
var list = new List<dynamic>();
var liststring = new List<string>();
foreach (dynamic a in list)
{
liststring.Add(a.ToString());
}
It compiles as expected, because again the a is declared as dynamic in foreach statement.
According to dynamic type docs:
The dynamic type indicates that use of the variable and references to its members bypass compile-time type checking. Instead, these operations are resolved at run time.
Type dynamic behaves like type object in most circumstances. In particular, any non-null expression can be converted to the dynamic type. The dynamic type differs from object in that operations that contain expressions of type dynamic are not resolved or type checked by the compiler.
There is no way to infer type from usage in case type checking and/or resolution is bypassed at compile-time.
If you omit generic type parameter it will by default return dynamic type even you call ToString() method. The reason is that any non-null expression can be assigned to dynamic. As dynamic is source, it will be also the result of Select(x => x.ToString()) method call.
On the other hand you can assign dynamic object to string variable as you are calling ToString() which returns string instance.

C# list in function param

I'm new to C#. I want to take a list as argument and return another from the data I get from the first one.
private List<DestinationGenericMapProps> ConstructDestinationMapPropsList(List<BoutiqueInWebService> datas)
{
var result = new List<DestinationGenericMapProps>(datas);
return result;
}
I get this error:
Error 241 The best overloaded method match for System.Collections.Generic.List<VDDataUpdaterGeneric.DataObjects.DestinationGenericMapProps>.List(int) has some invalid arguments
I know this is probably pretty basic but I'm new to C# and struggle with this. Thanks for your help.
List<BoutiqueInWebService> is not a List<DestinationGenericMapProps>.
This will not work unless BoutiqueInWebService is derived from DestinationGenericMapProps.
Basically, there is a List<T>(IEnumerable<T>) constructor, but the T's have to be the same.
Either change your return type to List<BoutiqueInWebService> and change your new statement:
private List<BoutiqueInWebService> ConstructDestinationMapPropsList(List<BoutiqueInWebService> datas)
{
var result = new List<BoutiqueInWebService>(datas);
return result;
}
or change your parameter to be of type List<DestinationGenericMapProps>:
private List<DestinationGenericMapProps> ConstructDestinationMapPropsList(List<DestinationGenericMapProps> datas)
{
var result = new List<DestinationGenericMapProps>(datas);
return result;
}
Alternatively, if you know how to make a DestinationGenericMapProps from a BoutiqueInWebService, you can use System.Linq and perform a select against the argument:
private List<DestinationGenericMapProps> ConstructDestinationMapPropsList(List<BoutiqueInWebService> datas)
{
var result = datas.Select(x => new DestinationGenericMapProps() { ... }).ToList();
return result;
}
Your method return type is a list of DestinationGenericMapProps, but you're trying to create list of BoutiqueInWebService (which is data).
You can do this to match your return type:
private List<DestinationGenericMapProps>
ConstructDestinationMapPropsList(List<BoutiqueInWebService> datas)
{
return (from d in datas
select new DestinationGenericMapProps()
{
// map properties here
Prop1 = d.SomePropInData
}).ToList();
}
You're getting the error because you're trying to populate a list of one type (DestinationGenericMapProps) with objects from a list of a different type (BoutiqueInWebService) which isn't type safe.
You can only do this if BoutiqueInWebService inherits from DestinationGenericMapProps.
C# supports function overloading, which means that a class can have more than one function with the same name as long as the parameters are different. The compiler decides which overload to call by compairing the types of the parameters. This applies to constructors too.
The List class has a three overloads of its constuctor:
List<T>()
List<T>(IEnumerable<T>)
List<T>(int)
I assume that you are trying to use the second of those as it will create a new list from the passed in one. For the list you are creating T is a DestinationGenericMapProps. So the constructors are:
List<DestinationGenericMapProps>()
List<DestinationGenericMapProps>(IEnumerable<DestinationGenericMapProps>)
List<DestinationGenericMapProps>(int)
The list you have passed in has T set to BoutiqueInWebService. As such the compiler is trying to find a constructor like this in the list above.
List<DestinationGenericMapProps>(IEnumerable<BoutiqueInWebService>)
As it can't find one it raises the error you have recieved.
Is it possible to cast a BoutiqueInWebService to a DestinationGenericMapProps object? If so you could do this:
var result = datas.Cast<DestinationGenericMapProps>().ToList()
If no direct cast is possible it may be possible to do a long hand cast like this:
var result = datas.Select(o => new DestinationGenericMapProps() { PropA = o.PropA, PropB = o.PropB /* etc */}).ToList();

Cannot implicitly convert type System.Collections.Generic.Dictionary<System.Tuple<int,int,string>, AnonymousType#1>

I have the following dictionary in a method:
var nmDict = xelem.Descendants(plantNS + "Month").ToDictionary(
k => new Tuple<int, int, string>(int.Parse(k.Ancestors(plantNS + "Year").First().Attribute("Year").Value), Int32.Parse(k.Attribute("Month1").Value), k.Ancestors(plantNS + "Report").First().Attribute("Location").Value.ToString()),
v => {
var detail = v.Descendants(plantNS + "Details").First();
return
new
{
BaseHours = detail.Attribute("BaseHours").Value,
OvertimeHours = detail.Attribute("OvertimeHours").Value
};
});
I need to return nmDict. The problem is that I cannot figure out how to label my method signature. I have tried the following:
protected IDictionary<XElement, XElement> OvertimereportData(HarvestTargetTimeRangeUTC ranges)
The above gives me this error:
Cannot implicitly convert type System.Collections.Generic.Dictionary<System.Tuple<int,int,string>,AnonymousType#1>' to 'System.Collections.Generic.IDictionary<System.Xml.Linq.XElement,System.Xml.Linq.XElement>'. An explicit conversion exists (are you missing a cast?)
protected IDictionary<Tuple, XElement> OvertimereportData(HarvestTargetTimeRangeUTC ranges)
gives me this error:
'System.Tuple': static types cannot be used as type arguments
I do not know what to do.
The short answer: You can't return anonymous types from a function.
The long answer: Your dictionary's value type is anonymous {BaseHours, OvertimeHours} which cannot be returned from a function or passed as an argument (except as an object, but that does nobody any good unless you go through the hassle of reflecting into it). Either define a class/struct with BaseHours and OvertimeHours in it, or use a tuple. The former is probably slightly better because you can keep the names BaseHours and OvertimeHours; with a tuple you just get Value1 and Value2.
If you are using C# 4.0 than you can return the anonymous via dynamic type. So your method signature would look like this
protected IDictionary<Tuple<int,int,string>, dynamic> OvertimereportData(HarvestTargetTimeRangeUTC ranges)
And through the dynamic object you can find the properties at run time.
Hope this will help you.
When you call the ToDictionary method, the resulting dictionary's type has little to do with the type of elements in your source sequence. It's defined entirely by the data types returned by the key and value expressions you supply to the call. For example, if you were to call:
xelem.Descendants(plantNS + "Month").ToDictionary(
k => int.Parse(k.Attribute("Year").Value),
v => k.Attribute("Year).Value
);
You would get an IDictionary<int, string> because that's what your two expressions returned. To return that from a method, you just need to construct the correct type, based on your expressions.
Your first one is easy:
k => new Tuple<int, int, string>(...)
The second one, though, is going to be a problem. The values in your dictionary are of an anonymous type: you return a new { } without specifying a concrete type name for that value. In general, that is going to make it impossible for you to use that dictionary as a return value or parameter. (It can be done, using some very strange-looking generic techniques, but I wouldn't recommend it.)
The first thing you'll need to do, then, is make a concrete type to hold your values, e.g.
public class HoursContainer
{
public string BaseHours { get; set; }
public string OvertimeHouse { get; set; }
}
and change your Linq query appropriately:
var detail = v.Descendants(plantNS + "Details").First();
return new HoursContainer
{
BaseHours = detail.Attribute("BaseHours").Value,
OvertimeHours = detail.Attribute("OvertimeHours").Value
};
Once you've done this, your dictionary will have a concrete type based on the types of things you specified when you created it:
IDictionary<Tuple<int, int, string>, HoursContainer>
(Note: You could also just use another Tuple<int, int> or whatever here, if you wanted, but the resulting generic type would get unwieldy very fast.)

Trouble with type casting in c#

I have 2 classes:
class A {
public void A_1(Object b) {
...
Type t = b.GetType();
(t.FullName)b.B_1(); //It doesn`t work! Error in cast
}
....
}
class B {
public void B_1() {
...
}
....
}
A a = new A();
B b = new B();
a.A1(b);
How to cast object correctly?
If you want to cast an object of any type to an object of another type, you do this:
// Will Throw an exception at runtime if it cant be cast.
B newObject = (B)oldObject;
// Will return null at runtime if the object cannot be cast
B newObject = oldObject as B;
// If in a generic method, convert based on the generic type parameter regardless of condition - will throw an exception at runtime if it cant be cast
B newObject = (T)Convert.ChangeType(oldObject, typeof(T))
Your syntax is off; you don't convert from the fullname to the object, you simply convert from the type symbol.
double x = (double)40;
ClassB anotherInstance = (ClassB)someOtherInstance;
What you're trying to do is basically:
Foo myFoo = ("Foo")myObject;
That definitely will not work in C#. When you cast in C#, the compiler emits code that does the cast, it needs to know what it's casting from and to, in order to write that code. A string does not help the compiler out here.
As others have pointed out, what you want to do doesn't seem like you really need to (unless this is just a contrived example). If you really want to do this, you'll need to work with a more dynamic language than C#, or find a C# friendly way of accomplishing this.
Are you sure you didn't mean to do (B)b.B_1()?
C# has a static type-system, i.e. all types must be known at compile-time (modulo reflection). So, casting to a type that is only known at run-time makes no sense. Specify the type explicitly:
public void A_1(object obj)
{
...
B b = (B)obj;
b.B_1();
// or
((B)obj).B_1();
}
You can also do this:
class A {
public void A_1(Object b) {
...
if (b is B)
{
((B)b).B_1();
}
}
....
}
Type.FullName is just a string; it's not a type. Use this instead: ((B)b).B_1(); Also, using GetType() is a way to get the type of an object dynamically, but casting is only possible or useful when the target type is known at compile time (not dynamic at all). In order to cast, simply refer to the type directly in a pair of parentheses. Don't attempt to obtain or use an object of type Type.

C#: How can I use implicit cast operator during object to type conversion?

HI!
Here is my case: I have some value type which is wrapped into another type with appropriate implicit converters. If I cast wrapped type to an object and then try to get original value I can do that in two-step cast only.
If simplified my code is as follows:
public enum MyEnum : int
{
First,
Second
}
public class Test<T>
{
public Test(T val)
{
Value = val;
}
private T Value { get; set; }
public static implicit operator T(Test<T> m)
{
return m.Value;
}
public static implicit operator Test<T>(T m)
{
var res = new Test<T>(m);
return res;
}
}
static void Main()
{
object res = new Test<MyEnum>(MyEnum.First);
Console.WriteLine((MyEnum)(Test<MyEnum>)res);
Console.WriteLine((MyEnum)res);
}
First "Console.WriteLine" works OK. Second one fails.
Is there any way I can modify this behavior and get it working without double casting?
UPDATE 1
I must use object to value cast (in real application I have to cast ComboBox.SelectedItem property and I do not want to add extra property to ComboBox, because I'll have to change my UI interaction code everywhere).
UPDATE 2
Implicit conversions to and from System.Object are not allowed.
UPDATE 3
Updated my sample code to reflect the whole problem.
Don't use object that way. Write your first line like this instead:
Test res = new Test(1);
If you must have it in an object first, remember that all the compiler knows about it at this point is that it's an object, and nothing more. You, as the programmer, have additional information about what you expect this object to be, but for the compiler to take advantage of that information you have to put it into your code somewhere.
Update:
I'm glad I was able to find this again, because this almost-very-timely article by Eric Lippert, who works on the C# language design, went up this morning and explains the problem in depth:
http://blogs.msdn.com/ericlippert/archive/2009/03/19/representation-and-identity.aspx
If you want to simplify casting and not care performance effect, then create extension method.
public static T To<T>(this object obj) {
Type type = obj.GetType();
MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Static);
MethodInfo method = methods.FirstOrDefault(mi => (mi.Name == "op_Implicit" || mi.Name == "op_Explicit") && mi.ReturnType == typeof(T));
if (method == null)
throw new ArgumentException();
return (T)method.Invoke(null, new[] { obj });
}
Usage
Console.WriteLine(res.To<MyEnum>());
Instead of adding implicit operators, consider implementing IConvertible. You only need to implement the ToInt32 method, the others are meaningless and you can throw the InvalidCastException in the other methods.
After that, you can use Convert.ToInt32() method to convert your object in one step.
or even
var res = new Test(1);
Your local variable res is always of type object; so the line that isn't working is trying to convert an object, that isn't an int, to an int, which can't be done. Same as this fails:
object d = 5.5d;
Console.WriteLine((int)d);
EDIT:
Perhaps a pattern that might help is something like this:
if (res.GetType() == typeof(Test))
{
Console.WriteLine((int)(Test)res);
}
else
{
Console.WriteLine((int)res);
}
It's a very localized solution to your problem, but perhaps it will work for you.
While the error is due to res being of type object, I would make the Test->int operator explicit...

Categories