C# implicit conversions - c#

I'm currently working on an application where I need to load data from an SQL database and then assign the retrieved values into the properties of an object. I'm doing this by using reflection since the property names and column names are the same. However, many of the properties are using a custom struct type that is basically a currency wrapper for the decimal type. I have defined an implicit conversion in my struct:
public static implicit operator Currency(decimal d)
{
return new Currency(d);
}
This works fine when I use it in code. However, when I have this:
foreach (PropertyInfo p in props)
{
p.SetValue(this, table.Rows[0][p.Name], null);
}
It throws an ArgumentException stating that it cannot convert from System.Decimal to Currency. I'm confused since it works fine in any other circumstance.

Unfortunately, these user-defined conversion operators are not used by the runtime; they are only used by the compiler at compile time. So if you take a strongly-typed decimal and assign it to a strongly-typed Currency, the compiler will insert a call to your conversion operator and everybody's happy. However, when you call SetValue as you're doing here, the runtime expects you to give it a value of the appropriate type; the runtime has no idea that this conversion operator exists, and won't ever call it.

I think you need to first unbox the value in table.Rows[0][p.Name] as a decimal.
In other words:
foreach (PropertyInfo p in props)
{
if (p.PropertyType == typeof(Currency))
{
Currency c = (decimal)table.Rows[0][p.Name];
p.SetValue(this, c, null);
}
else
{
p.SetValue(this, table.Rows[0][p.Name], null);
}
}
This is an issue I've seen once or twice before, so I actually decided to write a blog post about it. Anybody looking for a little more explanation, feel free to give it a read.

I assume that table is of type DataTable in your code, so the first indexer returns a DataRow, and the second one returns an object. Then PropertyInfo.SetValue also takes an object as the second argument. At no place in this code a cast happens in the code, which is why the overloaded conversion operator is not applied.
Generally speaking, it is only applied when static types are known (forgetting about dynamic in C# 4.0 for the moment). It is not applied when boxing and unboxing things. In this case, the indexer on DataRow boxes the value, and PropertyInfo.SetValue tries to unbox it to a different type - and fails.

Whilst I am not answering your problem, I think in this kind of situation it would be more appropriate to use a ORM Framework like the Entity Framework or NHibernate which will map your tables into your domain objects and handle all the conversions for you. Using something like reflection to figure out what fields to fill in a domain object is a slow way to do it.

Related

Difference between named field and named column in datatable

What is the difference bewteen the two below please?
var dtime = (DateTime)datatable[0]["SomeDateTime"];
var dtime = datatable[0].field<DateTime>("SomeDateTime");
EDIT
and this:
var dtime = Convert.ToDateTime(datatable[0]["SomeDateTime"]);
The difference is that the first uses an explicit cast by yourself whereas the second casts behind the scenes in the DataRow extension method Field.
So if the datetime-column can contain null-values you would use DateTime?:
DateTime? dtime = datatable.Rows[0].Field<DateTime?>("SomeDateTime");
So i would suggest to use Field. It's strongly typed(hides the cast) and supports nullable types. The explicit cast via (TypeName) is also less readable.
In the first line
var dtime = (DateTime)datatable[0]["SomeDateTime"];
you use the indexer property that returns an object. So you need to cast it yourself to the actual type you expect the object to be.
The second case
var dtime = datatable[0].Field<DateTime>("SomeDateTime");
calls the generic extension method Field<T> that tries to do the casting for you and returns the type you specified (so DateTime in your example).
You can inspect the different implementation in the reference source for the indexer and the Field<T>() extension method
The main difference between the examples given is the method of conversion
(Type) takes what ever type you have and forces it to become that type, erroring it not suitible
<Type> is passing in a generic type for the implementation of field to use in its typeless definition, which means that there is behind the scenes logic helping you convert
and Convert.ToType() is using the converter class to do the conversion, as its call required types to be compatible with the IConvertable interface this means someone has put some thought into making that type convertable which mean your likely to get a successful result
otherwise you are just using different means to access the named field (either the this property or the field method

Casting to custom type, Enumerable.Cast<T> and the as keyword

This is more a question out of curiosity than necessity and came about having had to deal with Active Directory (MS) types such as SearchResultCollection (in the System.DirectoryServices namespace).
Frequently when dealing with AD in code, I find that I'm having to check values for null, Count, [0] .. whatever and convert what I get out .. all the while hoping that the underlying AD object via COM doesn't go poof etc.
After having a play about with Parallel.ForEach recently - and having to pass in an IEnumerable<T>, I thought, maybe it would be fun to see how I could cast a SearchResultCollection to an IEnumerable of my own custom type. In this type I would pull out all the values from the SearchResult object and stick them in my own, .NET managed code. Then I'd do away with the DirectoryEntry, DirectorySearcher etc. etc.
So, having already worked out that it's a good idea to do searchResultCollection.Cast() in order to supply Parallel.ForEach with it's source, I added an explicit operator for casting to my own type (let's just call it 'Item').
I tested this out within the ParallelForEach, var myItem = (Item)currentSearchResult.
Good times, my cast operator is called and it all works. I then thought, it would be nice to do something like searchResultCollection.Cast<Item>(). Sadly this didn't work, didn't hit any breakpoints in the cast operator.
I did some Googling and discovered a helpful post which Jon Skeet had answered:
IEnumerable.Cast<>
The crux of it, use .Select(...) to force the explicit cast operation. OK, but, hmmm.
I went off and perhaps disassembled System.Core -> System.Linq.Enumerable.Cast<TResult>, I noticed that this 'cast' is actually doing an 'as' keyword conversion under the hood:
public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source)
{
IEnumerable<TResult> enumerable = source as IEnumerable<TResult>;
if (enumerable != null)
{
return enumerable;
}
if (source == null)
{
throw Error.ArgumentNull("source");
}
return CastIterator<TResult>(source);
}
I read some more and found this:
Implicit/Explicit conversion with respect to the "as" keyword
The top answer here states that 'as' doesn't invoke any conversion operators .. use a (cast). Semantically I find this a little weird, since the extension method is called cast.. Shouldn't it be casting? There will no doubt be a really good reason why this doesn't happen, anyone know what it is?
Even if it would have used the cast operator instead of as it still wouldn't be invoking user defined explicit operators, so it wouldn't matter. The only difference would be the type of exception thrown.
Explicit operators aren't known at all by the runtime. According to the CLR there is no way to cast your search result to Item. When the compiler notices that there is a cast that matches a given explicit operator it injects at compile time a call to that explicit operator (which is basically a static method) into the code. Once you get to runtime there is no remaining knowledge of the cast, there is simply a method call in place to handle the conversion.
Because this is how explicit operators are implemented, rather than providing knowledge to the runtime of how to do the conversion, there is no way for Cast to inject the explicit operator's call into the code. It's already been compiled. When it was compiled there was no knowledge of any explicit operator to inject, so none was injected.
Semantically I find this a little weird, since the extension method is called cast.. Shouldn't it be casting?
It's casting each element if it needs to, within CastIterator... although using a generic cast, which won't use explicit conversion operator you've defined anyway. You should think of the explicit conversion operator as a custom method with syntactic sugar over the top, and not something the CLR cares about in most cases.
For for the as operator: that's just used to say "If this is already a sequence of the right type, we can just return." It's used on the sequence as a whole, not each element.
This can actually cause problems in some slightly bizarre situations where the C# conversion and the CLR conversions aren't aligned, although I can't remember the example I first came upon immediately.
See the Cast/OfType post within Edulinq for more details.
If I understand correctly you need a DynamicCast which I wrote sometime ago.
Runtime doesn't know about implicit and explicit casting; it is the job of the compiler to do that. but using Enumerable.Cast<> you can't get that because Enumerable.Cast involves casting from System.Object to Item where there is no conversion available(you have conversion from X to Item, and not Object to Item)
Take the advantage of dynamic in .Net4.0
public static class DynamicEnumerable
{
public static IEnumerable<T> DynamicCast<T>(this IEnumerable source)
{
foreach (dynamic current in source)
{
yield return (T)(current);
}
}
}
Use it as
var result = collection.DynamicCast<Item>();
It is casting. See the implementation of CastIterator.
static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source) {
foreach (object obj in source) yield return (TResult)obj;
}
The use of the as keyword here is only to check if the entire collection can be casted to your target instead of casting item by item. If the as returns something that isn't null, then the entire collection is returned and we skip the whole iteration process to cast every item.
For example this trivial example would return a casted collection instead of iterating over every item
int?[] collection = ...;
var castedCollection = collection.Cast<int?>()
because the as works right off the bat, no need to iterate over every item.
In this example, the as gives a null result and we have to use the CastIterator to go over every object
int?[] collection = ...;
var castedCollection = collection.Cast<object>()

Using generics instead of casting for AsEnumerable

I am new to generics in C# and while reading a book stumbled upon an example:
var cars = from car in data.AsEnumerable()
where
car.Field<string>("Color") == "Red"
select new
{
ID = car.Field<int>("CarID"),
Make = car.Field<string>("Make")
};
The author says that car.Field<string>("Color") gives the additional compile-time checking comparing to (string)car["Color"]. But how does the compiler know that car.Field<string>("Color") is compilable for "Color" and not for "CarID"? Or there is some kind of another "additional compile-time checking" that I miss?
It doesn't give you any additional compile-time checking. If you use the wrong type, in both cases you'll get an exception during run-time.
But it can be useful to do additional stuff that simple cast can't. For example Field<int>("CarId") could call a method that converts the string in the field to an int.
And assuming you're talking about DataRow.Field<T>(), then, according to the documentation, it's useful mostly for dealing with null values and nullable types correctly.
The compiler doesn't know, your specifying that field "Color" is of type string. Internally, the Field<T>() method does it's magic to make that happen.
If you perform a cast ((string)car["Color"]) you could encounter a runtime exception if the field value cannot be converted to the destination type.
From memory, if you specify car.Field<string>("ColorID"), you will be able to safely convert int to string without any issues.
Specifically, the real benefit of car.Field<string>("Color") is that it encapsulates testing field values for equality with DBNull.Value, making your code cleaner and easier to read.
In your example, if the value of the "Color" field is null, the Field<T> extension method will return null, while car["Color"] will return DBNull.Value. You can't cast DBNull.Value to string, so the expression (string)car["Color"] raises an InvalidCastException in that case.
Before the development of the DataSetExtensions class, you would need a somewhat verbose expression to assign the value of that field to a string variable:
var color = DBNull.Value.Equals(car["Color"]) ? null : (string)car["Color"];
Another benefit of Field<T> is, as svick notes, that it enables you to work with nullable types and reference types using the same syntax.

Object to System.String implicit conversion

I have a question regarding type conversion in C#.
Object data_obj = "test";
string data_str;
data_str = data_obj;
this produces an error claiming no implicit conversion exists. Now, this is, at least for me, a little bit unintuitive, since Console.WriteLine("type{0}",data_obj.GetType()) produces System.String, but then again, i am really new at C#.
Now, getting past this, i would like to cast to the type of the data stored in data_obj, without having to switch and selecting the type manually.
So, basically, what i am asking is: is there a way to define an implicit conversion from System.Object to System.String, System.Decimal, etc.
Context:
I am reading from an ODBC connection to an SQLServer database and trying to pump those rows into an Oracle Database. Now, the correspondence of SQLServer and Oracle rows have to be defined. Now, i read the data from the SQLServer table with no problem whatsoever, and i store it in a List<Dictionary<string,Object>> (i know, storing the rows seem wrong, but design requirements, what can you do).
The insertion part is where i am having problems with the insertion. I basically loop (with a foreach) through the elements of the list and insert them row by row. It is here where i need to determine the type of the data stored in the Object.
Edit: Including a bit more detail.
No, there's no way of doing it implicitly. Options:
Call ToString() explicitly (which will throw an exception if the reference is null)
Call Convert.ToString()
Use "" + data_obj (ick, don't do it)
Cast if you're sure that data_obj is really a string
Why are you so keen on an implicit conversion though?
What you should be doing in your code as noted above is casting, not converting. The object in question is a string; you simply have stored it in an object reference.
Casting would be done like so:
data_str = (string)data_obj;
The overload of Console.Writeline you are mentioning takes a format string, and then a params array of object... not strings. It calls ToString() on each of those objects. So your call to data_obj.GetType().ToString() could be slimmed down to data_obj.GetType() (calling ToString() on a string just returns the string again)
As for an implicit conversion from object to type x... think about what you are asking; a reference of object can be any CLR type. How do you handle those conversions?
You could use the Convert.ToString method:
object o = ...
string s = Convert.ToString(o);
There is no implicit conversion from object to string in C#. However you could call the object's virtual ToString method
string s = o.ToString();
If you store your value in a var instead of type object and let the compiler decide what the value is, then it can be made implicit.
var data_obj = "test";
string data_str;
data_str = data_obj;

Casting woes with generic class which needs to know the specific value of T (out of a possible 30 different types) - is this scalable?

I am working with a 3rd party web testing API which has a Src property for image.
What I need to do is say:
if (t is HtmlImage) { // Do cast here. } // t is a variable of type T (my generic).
However, my cast does not work. The cast is as follows:
Controls.HtmlImage img = (Controls.HtmlImage)t;
This gives an error stating that I cannot convert Type 'T' to HtmlImage. BUT type T is the base class for all controls, including HtmlImage.
The problem I am trying to solve is I have a utility method to loop through a site's pages, but if I am passing Html Image as the value of T, I get the src property as I need the paths (to identify which images have no alt tags, and the src property can never be null). If T is of another type, I will get another property as an identifier. I am testing if images have alt tags, links have meaningful descriptions, etc. For a possible type total of about 30, is this scalable? Because I will be saying if T is Button, else, etc etc for quite a lot of types (could use table driven method).
HtmlImage inherits from:
public class HtmlImage : ArtOfTest.WebAii.Controls.HtmlControls.HtmlControl
T is of type HtmlControl
Thanks
You can't cast because the compiler doesn't necessarily know what a cast would mean. Casts can be used for boxing, unboxing, user-defined conversions or straight reference type conversions. The latter is what you're most interested in.
On the other hand, "as" works because it's always just a reference type conversion (unless you use it with a nullable type as the right hand operand).
In fact, you can use a cast, but only if you go through object first (which would always be either a boxing conversion or a reference conversion, but never a user-defined conversion):
HtmlImage hi = (HtmlImage) (object) hi;
I'd use as though, personally...
To answer my own question, this doesn't through a design time error:
Controls.HtmlImage img = t as Controls.HtmlImage;
But why doesn't the () operator work normally?
The other question left is the scalability of this sort of approach. Is there another, better, way?
I am not sure to understand. Try to add where T : HtmlImage in your methode definition
Controls.HtmlImage img = t as
Controls.HtmlImage;
But why doesn't the () operator work
normally?
When using the "as" keyword, a cast is invoked but when this doesn't succeed, like when img == null then it will return null. A cast through () will generate a exception when the cast didn't succeed.

Categories