Dynamic casting in c#

  • Thread starter Thread starter andrewbb
  • Start date Start date
A

andrewbb

I've seen this asked before, but haven't found a good solution. How
can you cast an object to a type when you don't know the type until
runtime? Specifically:


DataSet ds = new DataSet();
ds.ReadXml(@"c:\Temp\Test.xsd", XmlReadMode.ReadSchema);

DataTable table = ds.Tables["TestClass"];
DataRow row = table.Rows.Find("1d3b7bf2-61f1-4792-8ec5-a7337e44af03");

DataColumn col;
object val;

//Assigning values works fine with Guid/DateTime and value types:
col = table.Columns["_guid"];
val = row[col];

Console.WriteLine(col.DataType); //returns System.Guid
Console.WriteLine(row[col] is Guid); //returns true


//But now try that with another type that isn't Guid/DateTime:
col = table.Columns["_enum"];
val = row[col];

Console.WriteLine(col.DataType); //returns System.DayOfWeek
Console.WriteLine(row[col] is System.DayOfWeek); //returns false


So.... how can you get the value in row[col] into a System.DayOfWeek
variable?







In case you're interested, here's the XML for Test.xsd:

<?xml version="1.0" standalone="yes"?>
<StartupManager>
<xs:schema id="StartupManager" xmlns=""
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="StartupManager" msdata:IsDataSet="true">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element name="TestClass">
<xs:complexType>
<xs:sequence>
<xs:element name="_guid" msdata:DataType="System.Guid,
mscorlib, Version=1.0.5000.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" type="xs:string" />
<xs:element name="_enum"
msdata:DataType="System.DayOfWeek, mscorlib, Version=1.0.5000.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089" type="xs:string"
minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
<xs:unique name="Constraint1" msdata:PrimaryKey="true">
<xs:selector xpath=".//TestClass" />
<xs:field xpath="_guid" />
</xs:unique>
</xs:element>
</xs:schema>
<TestClass>
<_guid>1d3b7bf2-61f1-4792-8ec5-a7337e44af03</_guid>
<_enum>2</_enum>
</TestClass>
</StartupManager>
 
System.DayOfWeek weekday = (System.DayOfWeek)row[col];

--
HTH,

Kevin Spencer
Microsoft MVP
..Net Developer
A watched clock never boils.
 
Thanks, but this is a component that doesn't necessarily know this is
of type DayOfWeek at compile time. At runtime it does know the type
from reading col.DataType
 
So cast it as that type.

--
HTH,

Kevin Spencer
Microsoft MVP
..Net Developer
A watched clock never boils.
 
Declare an object and then at declaration type case it tothe type it should
be.

Object MyRowVal ;

switch (col.DataType)
{
case "System.DayofWeek":
MyRowVal = (System.DayofWeek)val;
break;

case "System.DayofYear":
MyRowVal = (System/DayofYear)val;
}


Use MyrowVal ahead instead of Val;
 
That would work *if* all the possible types were known at compile time.
But suppose the type is not DayOfWeek, but MyEnum.

I know the type at runtime. It's populated in Column.DataType
(retrieved from the msdata attribute in the dataset's XML). But
getting that value into a variable of the correct type on a dynamic
basis is the difficult part.

As an aside, if the runtime does type checking before all casts, why do
you need to know the type to cast to at compile time?
 
I've seen this asked before, but haven't found a good solution. How
can you cast an object to a type when you don't know the type until
runtime?

Casting tells the compiler that you know more information than it does.
In this case, you *don't* know more information than it does.

What would you to do with the result of the cast anyway?
 
But I will know more than the compiler at runtime: I know the type it
should be cast to. The reason I don't know at compile time is because
the result of the cast is set on an instance of an unknown object of
unknown type. eg. myFieldInfo.SetValue(myObject, val).

ADO.NET handles this under the hood for Guid and DateTime (maybe other
custom types as well) and creates an object of type Guid or DateTime
when it builds the dataset, assigning that value to the row/col.

I've found a workaround for enums (Enum.Parse(typeof(MyEnumType),
val)), but this still seems lacking in the language. I see no reason
to not be able to cast something dynamically at runtime.

The whole purpose is for a persistence layer that stores/loads any
object to/from any back-end data storage. (XML and SqlServer are
implemented at the moment). Set a [Persistable] attribute on any class
member and the persistence layer takes care of everything else. With
the Enum workaround I suppose it's solved... All major data types that
you might want to persist are now supported!
 
That is how I have done it in the past and it works well. Another cool
thing is if the Type is IConvertable, it can be converted automatically from
a string - which could also be xml, csv, or anything else you come up with.
 
But I will know more than the compiler at runtime: I know the type it
should be cast to.

But casts are only relevant at compile-time.
I've found a workaround for enums (Enum.Parse(typeof(MyEnumType),
val)), but this still seems lacking in the language. I see no reason
to not be able to cast something dynamically at runtime.

Then I'm afraid you haven't understood what everyone's been telling
you.

Casts allow you to tell the compiler: "I know that this reference which
you think is to type X is actually to type Y. Therefore, I'm going to
use it as a type Y object."

Now, you're not doing the second part - and the second part is the
whole reason for casting.
 
Back
Top