I'm trying to build a class which behaves like Nullable<T>, specifically the way I can access the underlying value of Nullable<T> class without having to explicitly call nullable.Value.
In the following example lines check1 & check2 both work.
Nullable<DateTime> nullable = new DateTime();
bool check1 = nullable >= DateTime.Now; //Works
bool check2 = nullable.Value >= DateTime.Now; //Works
I built my own class TrackedValue which remembers if the value it wraps has been changed. I've based mine on Nullable<T> and built the implicit & explicit operators.
Nullable<T> definition
public struct Nullable<T> where T : struct
{
public Nullable(T value);
public static explicit operator T(T? value);
public static implicit operator T?(T value);
...
}
TrackedValue<T> definition
public class TrackedValue<T> : IChangeTracking
{
...
T trackedValue;
public T Value
{
get
{
return this.trackedValue;
}
set
{
this.trackedValue = value;
}
}
public static explicit operator T(TrackedValue<T> value)
{
return value.Value;
}
public static implicit operator TrackedValue<T>(T value)
{
return new TrackedValue<T>() { Value = value };
}
}
So I was expecting the following to work, however check3 will not compile because of:
Argument 1: cannot convert from 'TrackedValue<System.DateTime>' to 'System.DateTime'
TrackedValue<DateTime> trackedValue = new DateTime();
bool check3 = trackedValue >= DateTime.Now; //Does not work
bool check4 = trackedValue.Value >= DateTime.Now; //Works
Any pointers would be appreciated.
That line specifically doesn't work because it requires an implicit conversion but you have it marked as explicit.
public class TrackedValue<T> : IChangeTracking
{
T trackedValue;
public T Value
{
get
{
return this.trackedValue;
}
set
{
this.trackedValue = value;
}
}
public static implicit operator T(TrackedValue<T> value)
{
return value.Value;
}
public static implicit operator TrackedValue<T>(T value)
{
return new TrackedValue<T>() { Value = value };
}
}
But naturally, you want to mimic the Nullable<T> model. So why does Nullable<T> <= T work implicitly but not yours? I believe it comes from the C# compiler itself. Eric Lippert has an excellent blog series on how Nullables are compiled/optimized.
From what I understand, the compiler itself alters the written code/IL to a different instruction set altogether. Eric's third entry on the series starts to demonstrate this. This is because it handles special cases for nulls generally I believe.
I'm not sure if you can work around this, but perhaps the simplest way is to simply mark the one conversion operator there as implicit instead and hope it doesn't cause any major issues for you with regards to consistency between TrackedValue<T> and Nullable<T>.
EDIT: One of those items of inconsistency will be say how comparisons are made.
Consider your line bool check3 = trackedValue >= DateTime.Now in the case that trackedValue is null. For a Nullable<DateTime> it goes kind of like this (note that this is not exactly what it is, see Eric's series. This is just for communicating the concept):
check3 = trackedValue.HasValue ? trackedValue.Value >= DateTime.Now : false;
The compiler avoids even calling the conversion operator. Yours on the other hand would attempt to run your implicit conversion (assuming you switch it to implicit) which could result in a NullReferenceException which is frowned upon (implicit operators should not throw exceptions). The reason why Nullable<T> defines the conversion operator as explicit is because for those times that you do directly cast (e.g., DateTime casted = (DateTime)myNullableDateTime;) can throw an exception if the value is null.
You declared your conversion operator explicit, so while bool check3 = trackedValue >= DateTime.Now; //Does not work, this should work:
bool check3 = (DateTime)trackedValue >= DateTime.Now;
The other course of action of course is to declare it implicit.
change the operator T to implicit:
public static implicit operator T(TrackedValue<T> value)
{
return value.Value;
}
Related
I have a custom class named Optional< T >. This class overrides the implicit operator, something like this:
public static implicit operator Optional<T>(T value)
{
return new Optional<T>(value);
}
public static implicit operator T(Optional<T> value)
{
return value.value;
}
Ok, till now all fine, the direct operations like these work:
Optional<int> val = 33; //ok
int iVal = val; //ok
But, this doesn't work:
Optional<Optional<int>> val = 33; //error, cannot convert implicitly
So I'm wondering how can be supported the previous case.
Cheers.
You cannot chain user-defined implicit operators. If you define an implicit conversion from A to B, and from B to C, there is no implicit conversion from A to C that calls both. You'll either need to create a separate user-defined conversion from A to C, or have an explicit conversion to do half of the conversion for you.
Out of curiosity, I explored overloading operators in C#. There is an interesting post by Eric Lippert discussing the design decisions in C++ and C# concerning operator&&. In C# its overloads are defined implicitly by overloading operator& plus overloading the boolean operators trueand false, which allows the language to preserve the sometimes essential short-circuit semantics.
Playing with the somewhat exotic operator true() and false() I found that I was not able to call them directly. Instead, they are implicitly called in certain places where a bool is required. As far as I can see, these are the language constructs which directly require a bool, namely the ternary conditionaly operator and the if clause, plus calls to operator&& resp. || when the argument type has overloaded operators & resp. |.
Edit: The book "The C# Programming Language" (7.11) as well as the annotated C# Standard in 14.11.2 -- both found via google search result -- have a code example with a direct operator call which I didn't understand must be pseudo code. I tried to replicate that.
As an aside, it is harder to provoke a call to operator false(); the ternary conditional as well as an if clause always test by calling operator true(). It seems as if the only way to call it is by calling operator||().
The motivation to call the boolean operators explicitly is that it would be nice to define only one of them directly and define the other one in terms of that, so that the definitions are always consistent. Below is a little example program with a few things I tried. Is there a syntax which I missed?
using System;
namespace TriviallyTrue
{
public class T
{
public static bool operator true(T t) { Console.WriteLine("In op. true"); return true; }
public static bool operator false(T t) { return true; }
}
class Program
{
static void Main(string[] args)
{
T t = new T();
// bool b = T.true(t); // Identifier expected; 'true' is a keyword
// ok, I see. Let's use the keyword syntax.
// bool b = T.#true(t); //'TriviallyTrue.T' does not contain a definition for 'true'
// That's so not true!
// oh. perhaps we need to use cast syntax, akin to invoking operator int()?
// bool b = (true)t; // ; expected
// hm. It's in T's namespace...
// bool b = (T.true)t; // Identifier expected;
// we know that.
// another cast try.
// bool b = (T.#true)t; // The type name 'true' does not exist in the type 'TriviallyTrue.T'
// ah, a type is expected. Well, the type is bool, right? But casting to bool
// doesn't work either, see below and in Main().
// bool b = (T.#bool)t; // The type name 'bool' does not exist in the type 'TriviallyTrue.T'
// well, it exists *some*what
if (t) // works
{
// Console.WriteLine("t was " + (bool)t); // Cannot convert type 'TriviallyTrue.T' to 'bool'
// That's so not true!
Console.WriteLine("t was " + (t ? "True" : "False" )); // works!
}
}
}
}
Sample session:
In op. true
In op. true
t was True
I cannot answer the question in the title, but I think I can cover this part
The motivation to call the boolean operators explicitly is that it would be nice to define only one of them directly and define the other one in terms of that, so that the definitions are always consistent.
Without questioning in any way what #Eric Lippert wrote in that post, C# has an easier way of doing all that when a one of the true or false is logically the inverse on the other, which is the most common practical case. Instead of overriding 4 operators (false, true, & and |), one can simply provide a single implicit conversion to bool.
For instance
public class T
{
public static implicit operator bool(T t) { return t != null; }
}
Now all these work
T a = new T(), b = null;
if (a) { }
if (!a) { }
if (b) { }
if (!b) { }
if (a && b) { }
if (b && a) { }
if (a & b) { }
if (a || b) { }
if (b || a) { }
if (a | b) { }
var c1 = a ? 1 : 0;
var c2 = b ? 1 : 0;
You can't call any operator methods explicitly in C#. operator true and operator false are no exception. It's just that most operator methods have a more straightforward method of invoking them implicitly.
If it makes sense to call the operator method in other scenarios than as an overload operator, provide it as a regular method instead. It's generally more readable and can nicely avoid the whole problem of having multiple separate implementations that you wanted to solve.
public class T
{
private bool asBoolean() { ... } // or even make it public
public static bool operator true(T t) { return t.asBoolean(); }
public static bool operator false(T t) { return !t.asBoolean(); }
}
For completeness, you can implement operator false as e.g.
public static bool operator false(T t) { return t ? false : true; }
but please don't unless you absolutely need to.
I have a struct type in C#. I want to be able to convert null implicitly to this type. For instance, null could be represented by a special value of the struct type and the cast operator should return a struct with this value.
In C++, I could use an implicit cast operator overload of type std::nullptr_t. Is there a comparable type in C#?
I have had the idea to use a special NullType class which has no instances. This works but looks somehow ugly. Is there a better way?
Example:
class NullType
{
private NullType(){} // ensures that no instance will ever be created
}
struct X
{
private static readonly int nullValue = -1;
private int val;
public X(int val){ this.val= val; }
public static implicit operator X(NullType t)
{
return new X(nullValue);
}
}
class MainClass
{
public static void Main(string[] args)
{
X x = null; // Works now!
}
}
No, conversion operators only allow conversion from types, not from a specific value of a type, aka null, so there is no null conversion operator.
The best fitting operator without introducing own types would be this:
public static implicit operator X(object t)
But obviously you don't want to use this. It isn't very safe to use (t can be any value, and the only way to handle non-null cases in an exception).
That said, I think the way you've created it now, using a class that can't be initialized is the best way to do this. In fact the only question is: why do you want to use null, instead of 'just' an default value instance on your struct (X.Null).
I have been given a sample statement:
MyClass myclass = 3;
How is it possible to make this a valid statement? What code do I need to include in MyClass to support the implicit conversion from an int?
You need an implicit conversion operator:
public class MyClass
{
private readonly int value;
public MyClass(int value)
{
this.value = value;
}
public static implicit operator MyClass(int value)
{
return new MyClass(value);
}
}
Personally I'm not a huge fan of implicit conversions most of the time. Occasionally they're useful, but think carefully before putting them in your code. They can be pretty confusing when you're reading code.
On the other hand, when used thoughtfully, they can be amazingly handy - I'm thinking particularly of the conversions from string to XName and XNamespace in LINQ to XML.
Here's how:
public class MyClass
{
public static implicit operator MyClass(int i)
{
return new MyClass(i);
}
}
This uses C# feature called implicit conversion operator.
It's possible if MyClass has an implicit conversion from int.
Using Conversion Operators
Just implement an implicit conversion operator.
You need to overload the implicit constructor operator:
public static implicit operator MyClass (int rhs)
{
MyClass c = new MyClass (rhs);
return c;
}
Let's say you have yourself a class like the following:
public sealed class StringToInt {
private string _myString;
private StringToInt(string value)
{
_myString = value;
} public static implicit operator int(StringToInt obj)
{
return Convert.ToInt32(obj._myString);
}
public static implicit operator string(StringToInt obj)
{
return obj._myString;
}
public static implicit operator StringToInt(string obj)
{
return new StringToInt(obj);
}
public static implicit operator StringToInt(int obj)
{
return new StringToInt(obj.ToString());
}
}
Will you then be able to write code like the following:
MyClass.SomeMethodThatOnlyTakesAnInt(aString);
without it stating that there is no implicit cast from string to int?
[Yes, i could test it myself but i thought i would put it out there and see what all of the gurus have to say]
No C# won't call more than one user defined implicit conversion. From the C# spec section 6.4.3:
Evaluation of a user-defined conversion never involves more than one user-defined or lifted conversion operator. In other words, a conversion from type S to type T will never first execute a user-defined conversion from S to X and then execute a user-defined conversion from X to T.
I am fairly certain this is not possible under C# 3.0. The sections in the reference that covers conversions is 6.4. Namely, 6.4.4 "User-defined implicit conversions".
It only talks about conversions from S->T (and not S->T->U) which covers the cases such as:
StringToInt _t = "foo";
int t = _t;
and
int t = (StringToInt)"foo";
Where both of these cases only involve S->T (twice).
I am pretty sure this is not possible in C# 3.0.
Allowing S->T->U would require much more work to be performed by the type matcher, at least following the algorithm specified.
It does not appear to work. It requires at least one explicit cast. Oh well...
Typos in your snippet:
public StringToInt(string value)
{
_myString = value;
}
public static implicit operator int(StringToInt obj)
{
return Convert.ToInt32(obj._myString);
}
public static implicit operator string(StringToInt obj)
{
return obj._myString;
}
If aString is of type StringToInt, your usage should work.