Automatic type Conversion in C# - c#

I know that you could override an object's ToString() Method, so that everytime you call an object or pass it to a function that requires a String type it will be converted to a String.
I have written several extension methods for object type 'object'
public static DateTime ToDate(this object date)
{
return DateTime.Parse(date.ToString());
}
public static int ToInteger(this object num)
{
return Int32.Parse(num.ToString());
}
public static long ToLong(this object num)
{
return Int64.Parse(num.ToString());
}
so that I could just call them like this:
eventObject.Cost = row["cost"].ToString();
eventObject.EventId = row["event_id"].ToLong();
However, what I want to accomplish is to convert the row objects which is of type 'object' to its correct type based on the property types on my 'eventObject'. So, I could call it like this:
eventObject.Cost = row["cost"];
eventObject.EventId = row["event_id"];
The row is a DataRow if that matters.

C# supports implicit conversion for types and you can use it for your custom types like the following:
class CustomValue
{
public static implicit operator int(CustomValue v) { return 4; }
public static implicit operator float(CustomValue v) { return 4.6f; }
}
class Program
{
static void Main(string[] args)
{
int x = new CustomValue(); // implicit conversion
float xx = new CustomValue(); // implicit conversion
}
}
And supports extension methods, but doesn't support implicit conversion as an extension method like the following:
static class MyExtension
{
// Not supported
public static implicit operator bool(this CustomValue v)
{
return false;
}
}

I know that you could override an
object's ToString() Method, so that
everytime you call an object or pass
it to a function that requires a
String type it will be converted to a
String.
No, you are wrong. The following code won't compile:
class MyClass
{
public override string ToString()
{
return "MyClass";
}
}
static void MyMethod(string s) { }
static void Main(string[] args)
{
MyMethod(new MyClass()); //compile error
}
The compiler will not get the type of MyMethod parameter(which is string) first and try to convert the argument you passed(whose type is MyClass) to it. I guess you are probably mislead by something like Console.WriteLine. Base on the code above,
Console.WriteLine(new MyClass()) prints "MyClass" to the console, it seems that the compiler knows you should pass a string to Console.WriteLine and try to convert MyClass to string. But the essential is Console.WriteLine has several overloads, one of them is for object:
//from Console.cs
public static void WriteLine(object value)
{
//in this method there is something like
//Console.WriteLine(value.ToString());
}

I believe what you're looking for is implicit conversion, which is described here: http://msdn.microsoft.com/en-us/library/z5z9kes2.aspx.
However, adding these to object would be a very bad idea, for reasons outlined on the page I've linked to.

Forgive me if I'm stating the obvious but I got this impression after reading your question.
You know the basetype of every type in .NET is object right?
So the column in the datarow which you describe of type object could also just as well be of the same type as the member you're trying to assign to and then a simple cast is needed.
for instance
eventObject.EventId = (int)row["event_id"];

To sum up - just define these methods and you can use objects of class Test in methods requiring String as a parameter.
class Test
{
private String txt;
public static implicit operator string(Test t)
{
return t.ToString();
}
public override string ToString()
{
return txt;
}
}

Related

Extend "object" with a null check more readable than ReferenceEquals

I tried to extend "object" to allow a more readable check if an object is null.
Now, object.ReferenceEquals really checks for a null object, (the rare times it will not apply are since the operator == can be overridden. the object.Equals(null) method can also be overridden).
But the object.ReferenceEquals(null, obj); is not too readable is it?... So, I thought, why not write an extension method to the System.object that will provide that check using object.IsNull(obj);
I've tried:
public static class MyExtClass
{
// the "IsNull" extension to "object"
public static bool IsNull(this object obj)
{
return object.ReferenceEquals(obj, null);
}
}
public SomeOtherClass
{
public static void TryUsingTheExtension()
{
object obj;
// Why does this line fail? the extension method is not recognized
// I get: 'object' does not contain a definition for "IsNull"
bool itIsANull = object.IsNull(obj);
}
}
What did I miss?
Extension methods can be invoked only on instance and not on a class that they extend. So this line of code bool itIsANull = object.IsNull(obj); is incorrect because object is type and not an instance. Change it to :
bool itIsANull = (new object()).IsNull();
Or you can call it on class MyExtClass but not on object class (which is located in mscore.lib) :
MyExtClass.IsNull(new object());
P.S.
It looks like you missed something about extension methods. The truth is that they have nothing to do with classes that they extend. It's just a convenience that is provided for us by Intellisense with use of reflection.
Object class is located in mscorelib and is immutable. You can't add something to it. But what really happens is that Intellisense searches for all public methods that are located in public static classes and accept first argument with keyword 'this' as parameter. If one is found it's 'mapped' to the class that it extends. So when we type obj.MyExtMethod() on instance of that class it is automatically converted by compiler to Helper.MyExtMethod(obj); (if helper is our static class);
Try
bool itIsANull = obj.IsNull();
You wrote an extension method, and extension methods exist in a different type but extend objects of the specified type by another method.
But when you call object.IsNull(), then you are looking for a static method that exists on the object type.
Instead, you have two ways to call your method:
// either the static method on the class
MyExtClass.IsNull(obj);
// or using the actual feature of extension methods
obj.isNull();
Because it’s an extension method, the latter form will be automatically converted into the former at compile time.
You are calling the extension method on the object itself. You should call the methd on the instance instead -
bool itIsANull = obj.IsNull()
Try:
class Program
{
static void Main(string[] args)
{
var o = new object();
if (o.IsNull())
{
Console.Write("null");
}
}
}
public static class Request
{
public static bool IsNull(this object obj)
{
return ReferenceEquals(obj, null);
}
}
public static class MyExtClass
{
// the "IsNull" extension to "object"
public static bool IsNull(this object obj)
{
return object.ReferenceEquals(obj, null);
}
}
public class SomeOtherClass
{
public static void TryUsingTheExtension()
{
object obj =null;
bool itIsANull = obj.IsNull();
}
}

Using C# generics to create a mapper method with different return types

I am trying to create a method to map int to string and string to int. I had the idea to do it in a single method, but not really sure if this is possible.
I got this far:
class MappingWithGenerics
{
[Test]
public void IntToString()
{
string actual = Map<int, string>(1);
Assert.AreEqual("1", actual);
}
[Test]
public void StringToInt()
{
int actual = Map<string, int>("1");
Assert.AreEqual(1, actual);
}
public TOut Map<Tin, TOut>(Tin element)
{
if(element.GetType() == typeof(int))
return element.ToString();
return Convert.ToInt32(element);
}
}
this gives compilation errors.
Cannot implicitly convert type 'int' to 'TOut'
Cannot implicitly convert type 'string' to 'TOut'
Any idea how I could implement the Map method?
Generics are for when you want the same functionality across a bunch of different types. In this case, you're dealing with two specific types and you want different functionality between them. Generics aren't really what you want, especially when you can do the same thing with simple method overloading:
class MappingWithoutGenerics
{
public string Map(int x)
{
return x.ToString();
}
public int Map(string s)
{
return Convert.ToInt32(s);
}
}
The reason that your code does not compile is that you coded a generic method with only two specific types in mind. You can shoehorn this into a generic function with conversion to object, but this is not a good idea.
You can implement the desired functionality using the Convert class, like this:
public static TOut Map<Tin, TOut>(Tin element) {
return (TOut)Convert.ChangeType(element, typeof(TOut));
}
Your test methods will work without a change. However, the method will be capable of conversions beyond string->int and int->string: you will be able to convert between any pair of types supported by Convert.ChangeType method.
Demo.
You can implement the method like this:
public TOut Map<Tin, TOut>(Tin element)
{
object outValue;
if(element.GetType() == typeof(int))
outValue = element.ToString();
else
outValue = Convert.ToInt32(element);
return (TOut)outValue;
}
But I really wonder why do you need such a method. I'm sure there is better way to solve your broader problem.

Why do C# out generic type parameters violate covariance?

I'm unclear as to why the following code snippet isn't covarient?
public interface IResourceColl<out T> : IEnumerable<T> where T : IResource {
int Count { get; }
T this[int index] { get; }
bool TryGetValue( string SUID, out T obj ); // Error here?
}
Error 1 Invalid variance: The type parameter 'T' must be invariantly
valid on 'IResourceColl.TryGetValue(string, out T)'. 'T' is
covariant.
My interface only uses the template parameter in output positions. I could easily refactor this code to something like
public interface IResourceColl<out T> : IEnumerable<T> where T : class, IResource {
int Count { get; }
T this[int index] { get; }
T TryGetValue( string SUID ); // return null if not found
}
but I'm trying to understand if my original code actually violates covariance or if this is a compiler or .NET limitation of covariance.
The problem is indeed here:
bool TryGetValue( string SUID, out T obj ); // Error here?
You marked obj as out parameter, that still means though that you are passing in obj so it cannot be covariant, since you both pass in an instance of type T as well as return it.
Edit:
Eric Lippert says it better than anyone I refer to his answer to "ref and out parameters in C# and cannot be marked as variant" and quote him in regards to out parameters:
Should it be legal to make T marked as "out"? Unfortunately no. "out"
actually is not different than "ref" behind the scenes. The only
difference between "out" and "ref" is that the compiler forbids
reading from an out parameter before it is assigned by the callee, and
that the compiler requires assignment before the callee returns
normally. Someone who wrote an implementation of this interface in a
.NET language other than C# would be able to read from the item before
it was initialized, and therefore it could be used as an input. We
therefore forbid marking T as "out" in this case. That's regrettable,
but nothing we can do about it; we have to obey the type safety rules
of the CLR.
Here's the possible workaround using extension method. Not necessarily convenient from the implementor point of view, but user should be happy:
public interface IExample<out T>
{
T TryGetByName(string name, out bool success);
}
public static class HelperClass
{
public static bool TryGetByName<T>(this IExample<T> #this, string name, out T child)
{
bool success;
child = #this.TryGetByName(name, out success);
return success;
}
}
public interface IAnimal { };
public interface IFish : IAnimal { };
public class XavierTheFish : IFish { };
public class Aquarium : IExample<IFish>
{
public IFish TryGetByName(string name, out bool success)
{
if (name == "Xavier")
{
success = true;
return new XavierTheFish();
}
else
{
success = false;
return null;
}
}
}
public static class Test
{
public static void Main()
{
var aquarium = new Aquarium();
IAnimal child;
if (aquarium.TryGetByName("Xavier", out child))
{
Console.WriteLine(child);
}
}
}
It violates covariance because the value provided to output parameters must be of exactly the same type as the output parameter declaration. For instance, assuming T was a string, covariance would imply that it would be ok to do
var someIResourceColl = new someIResourceCollClass<String>();
Object k;
someIResourceColl.TryGetValue("Foo", out k); // This will break because k is an Object, not a String
Examine this little example and you will understand why it is not allowed:
public void Test()
{
string s = "Hello";
Foo(out s);
}
public void Foo(out string s) //s is passed with "Hello" even if not usable
{
s = "Bye";
}
out means that s must be definitely assigned before execution leaves the method and conversely you can not use s until it is definitely assigned in the method body. This seems to be compatible with covariance rules. But nothing stops you from assigning s at the call site before calling the method. This value is passed to the method which means that even if it is not usable you are effectively passing in a parameter of a defined type to the method which goes against the rules of covariance which state that the generic type can only be used as the return type of a method.

Having an ambiguity issue in C#

I have the follow program:
static void Main(string[] args)
{
CaptureFunction(MyFunction); // This line gets an error: "The call is ambiguous between the following methods or properties: CaptureFunction(System.Func<object,object>) and CaptureFunction(System.Func<int,int>)"
CaptureFunction(MyFunction2);
}
static void CaptureFunction(Func<object,object> myFunction)
{
myFunction.DynamicInvoke(3);
}
static void CaptureFunction(Func<int, int> myFunction)
{
myFunction.DynamicInvoke(3);
}
static object MyFunction(object a)
{
if (a is int)
return ((int) a)*3;
return 0;
}
static int MyFunction2(int a)
{
return a * 3;
}
I am trying to figure out why I am getting an ambiguity error at that line. They clearly have two different parameter signatures. I understand that an int can also be boxed into an object, however, I would except C# to call the CaptureFunction(Func<int, int>) method if I pass actual int values, otherwise it should call the other CaptureFunction() method. Can someone please explain this and please offer a possible work around?
This is due to covariance/contavariance introduced in .Net 4. See here for info. Because int is castable to object the compiler can't decide which function you are pointing to (as Func is castable to Func) Sorry, not .Net 4
The following compiles:
static void Main(string[] args)
{
CaptureFunction((Func<object,object>)MyFunction); // This line gets an error: "The call is ambiguous between the following methods or properties: CaptureFunction(System.Func<object,object>) and CaptureFunction(System.Func<int,int>)"
CaptureFunction(MyFunction2);
}
static void CaptureFunction(Func<object,object> myFunction)
{
myFunction.DynamicInvoke(3);
}
static void CaptureFunction(Func<int,int> myFunction)
{
myFunction.DynamicInvoke(3);
}
static object MyFunction(object a)
{
if(a is int)
return ((int)a)*3;
return 0;
}
static int MyFunction2(int a)
{
return a * 3;
}
Note the casting to Func<object,object>
Try to use dynamic if you are using C#.net 4.0
static void CaptureFunction(Func<dynamic, dynamic> myFunction)
{
myFunction.DynamicInvoke(3);
}
if you are not using 4.0 then just use object type.
static void CaptureFunction(Func<object, object> myFunction)
{
myFunction.DynamicInvoke(3);
}
remove the other overload of CaptureFunction which has a type of int.
You are passing a delegate for MyFunction... but which one? It could be either... either would work.
There are overloads of CaptureFunction that will accept either MyFunction signature. So it has no way to know which one you mean.
It seems like the function given satisfies both delegate signatures. You can work around this by declaring the func explicitly:
Func<int, int> intFunc = MyFunction2;
Func<object, object> objFunc = MyFunction;
CaptureFunction(intFunc);
CaptureFunction(objFunc);

How to perform conversion from object reference

class Mock
{
public static explicit operator String(Mock s)
{
return "ok";
}
}
static T GetValue<T>(object o)
{
return (T)o;
}
Mock m = new Mock();
var v1 = (string) m;
var v2 = GetValue<string>(m); // InvalidCastException is thrown.
// How to modify GetValue method
// internally, without changing its
// signature, for this casting to work ?
Regards
Two options:
Use reflection to find the conversion and invoke it
Use dynamic typing if you're using C# 4
Using reflection is likely to be painful. The dynamic approach is simpler if you can get away with it:
public static T GetValue<T>(dynamic d)
{
return (T) d;
}
That isn't a particularly drastic change to the signature, but if you wanted to keep it exactly the same, you could use:
public static T GetValue<T>(object o)
{
dynamic d = o;
return (T) d;
}
The reason the direct cast succeeds and the GetValue method fails is because the direct cast method is using the explicitcast operator on the Mock<T> type. This explicit cast operator is not available in the generic version because the C# compiler only sees T and hence doesn't bind to the implicit conversion operator but instead chooses to do a CLR conversion.
The easiest way to get this to work is to add an interface to represent this conversion and then constraint T to implement the interface
interface IConvertToString {
string Convert();
}
public class Mock : IConvertToString {
public string Convert() {
return "ok";
}
}
public static T GetValue<T>(T o) where T : IConvertToString {
return o.ConvertToString();
}
How about this: var v2 = GetValue<string>((string)m); ?
This does not modify the GetValue method, rather casts the parameter sent into it. You retain your signature. The cast looks a bit redundant but you have to specify the type for GetValue anyway...

Categories

Resources