Casting an object with a conversion operator fails - c#

So I have this Object, say DoubleContainer.
public struct DoubleContainer
{
private readonly double _value;
private DoubleContainer(double value)
{
_value = value;
}
public static implicit operator double(DoubleContainer doubleContainer)
{
return doubleContainer._value;
}
public static DoubleContainer Create(double value)
{
return new DoubleContainer(value);
}
}
Casting it works as expected in almost all cases, except where it's passed into a function as an Object.
The following code generates an InvalidCastException if I pass in a DoubleContainer:
public double GetDouble(Object input)
{
return (double)input;
}
I can get it to work if I do use dynamic:
public double GetDouble(Object input)
{
return (double)(dynamic)input;
}
My problem with this solution is that Visual Studio grays out the (dynamic), because it should be redundant, so someone may remove it. Also I don't know if there are any other places in the codebase where this same problem may occur.
Is there anything I can do to my implementation of DoubleContainer what will make my first implementation of GetDouble() work? I tried adding another implicit conversion operator from Object to DoubleContainer, but "user-defined conversions to or from a base class are not allowed"....

You cannot make it work, because you can only unbox boxed struct (this is what you are doing with (double) input) to the exact undelying type, for the reasons best described in this article by Eric Lippert. So whenever you do (double) someObject - it will only work if object is actually a double, not int, not float , not DoubleContainer. If you expect other types - you can better use Convert.ToDouble. For that to work with your type you need it to implement IConvertible:
public struct DoubleContainer : IConvertible
{
private readonly double _value;
private DoubleContainer(double value)
{
_value = value;
}
public static implicit operator double(DoubleContainer doubleContainer)
{
return doubleContainer._value;
}
public static DoubleContainer Create(double value)
{
return new DoubleContainer(value);
}
public double ToDouble(IFormatProvider provider) {
return _value;
}
public bool ToBoolean(IFormatProvider provider) {
// delegate to your double
return ((IConvertible) _value).ToBoolean(provider);
}
// ... rest is skipped ...
Then it will work with
public double GetDouble(Object input)
{
return Convert.ToDouble(input);
}

When casting an object to double, compiler does not know that it should call your existing operator double, so it will not insert any call to your user defined operator double.
When you insert dynamic in the middle, compiler will generate something like "if this reference has an operator double, call it`, so it works.
So, it actually cannot work as long as you cast a System.Object to a double, while code suggested by #juharr, slightly modified, will work:
public double GetDouble(Object input)
{
if (input is DoubleContainer)
{
var dc = (DoubleContainer)input;
return (double)dc;
}
return (double)input;
}
EDIT: modified code as per #SergiyKlimkov comment

Related

Create a method that can only take T as a parameter

I want to create a method that can only take a double as an argument.
If I write it like this:
public static void Foo(double d)
{
// ...
}
Then we can call Foo with ints, floats, doubles, etc. Like this:
public static void Main()
{
Foo(34); // int
Foo(1.3454365F); // float
Foo(34.12); // double
}
I tried to create a generic method that can only take a double as a parameter, like this:
public static void Foo<T>(T t) where T : double
{
// ...
}
But type double can not be used as a constraint.
How can I achieve this?
You can devise some types with implicit operators such that overload resolution will fail to decide a winner for some types but not others:
struct EvilDoubleWrapper
{
public double Value { get; }
public EvilDoubleWrapper(double value)
{
Value = value;
}
public static implicit operator EvilDoubleWrapper(double value) => new EvilDoubleWrapper(value);
public static implicit operator EvilDoubleWrapper(int value)
{
// If the program changes in such a way that this conversion is allowed to occur,
// we should at a minimum raise an assertion
Trace.Assert(true);
return default;
}
}
struct EvilOtherWrapper
{
public static implicit operator EvilOtherWrapper(int value) => default;
}
static void Main(string[] args)
{
Foo(1.23d); // Works
Foo(1); // Error CS0121: The call is ambiguous
}
static void Foo(EvilDoubleWrapper d)
{
// Use d.Value as your double
}
static void Foo(EvilOtherWrapper o)
{
// Does nothing; only exists to fault the overload resolver
}
Neither of EvilDoubleWrapper nor EvilOtherWrapper is "better" than other other for overload resolution, and since there's an implicit conversion from int to both of them, overload resolution will fail. But there is only one implicit conversion from double to either of those, so overload resolution will successfully pick that one. Define implicit conversions for other built-in conversions that you want to forbid as well -- there's a rather small, closed set of such conversions listed here.

32 bit implicit conversions fail generic overload resolution

I'm experimenting with custom integer types and came across an interesting issue involving generics, implicit conversions, and 32 bit integers.
Below is a stripped down example of how to reproduce the problem. If I have two implicit methods that convert int to MyInt and vice versa, I get a compilation error which looks like C# can't resolve which generic type to use. And it only happens with int or uint. All other integer types work fine: sbyte,byte,short,ushort,long,ulong.
If I remove one of the implicit conversion methods, it also works fine. Something to do with circular implicit conversions?
using Xunit;
public class MyInt
{
public int Value;
//If I remove either one of the implicit methods below, it all works fine.
public static implicit operator int(MyInt myInt)
{
return myInt.Value;
}
public static implicit operator MyInt(int i)
{
return new MyInt() { Value = i };
}
public override bool Equals(object obj)
{
if (obj is MyInt myInt)
{
return this.Value == myInt.Value;
}
else
{
int other_int = (int)obj;
return Value == other_int;
}
}
}
Below is the test code showing the compilation errors I get when both implicit methods are defined.
public class Test
{
[Fact]
public void EqualityTest()
{
MyInt myInt = new MyInt();
myInt.Value = 4 ;
Assert.Equal(4, myInt.Value); //Always OK which makes sense
//Compile errors when both implicit methods defined:
// Error CS1503 Argument 1: cannot convert from 'int' to 'string',
// Error CS1503 Argument 2: cannot convert from 'ImplicitConversion.MyInt' to 'string'
Assert.Equal(4, myInt);
}
}
I believe C# is complaining about not being able to convert both types to string as that is the type of the last Xunit.Assert.Equal() overload and all the others failed to match:
//Xunit.Assert.Equal methods:
public static void Equal<T>(T expected, T actual);
public static void Equal(double expected, double actual, int precision);
public static void Equal<T>(T expected, T actual, IEqualityComparer<T> comparer);
public static void Equal(decimal expected, decimal actual, int precision);
public static void Equal(DateTime expected, DateTime actual, TimeSpan precision);
public static void Equal<T>(IEnumerable<T> expected, IEnumerable<T> actual, IEqualityComparer<T> comparer);
public static void Equal<T>(IEnumerable<T> expected, IEnumerable<T> actual);
public static void Equal(string expected, string actual, bool ignoreCase = false, bool ignoreLineEndingDifferences = false, bool ignoreWhiteSpaceDifferences = false);
public static void Equal(string expected, string actual);
I don't think I've made a mistake with the implicit conversions as I can make other similar examples create the same problem when used with 32 bit ints.
I'm testing in a .NET Core 3.0 project.
Any help would be appreciated. Thanks!
Clarification:
What I would like to know is why this only fails with 32 bit integers. Implicit conversions are working (confirmed with debugging) when the types are anything else like the example below using a long.
using Xunit;
public class MyLong
{
public long Value;
public static implicit operator long(MyLong myInt)
{
return myInt.Value;
}
public static implicit operator MyLong(long i)
{
return new MyLong() { Value = i };
}
public override bool Equals(object obj)
{
if (obj is MyLong myInt)
{
return this.Value == myInt.Value;
}
else
{
long other_int = (long)obj;
return Value == other_int;
}
}
}
public class Test2
{
[Fact]
public void EqualityTest()
{
MyLong myLong = new MyLong();
myLong.Value = 4 ;
Assert.Equal(4, myLong); //NOTE! `4` is implicitly converted to a MyLong
//object for comparison. Confirmed with debugging.
}
}
Something to do with circular implicit conversions?
Yes (though, you've already demonstrated that much by showing that it works fine when one of the conversions is eliminated).
The reason this is happening with int, and not with other types, is that the type of your literal is int. This means that during overload resolution, the compiler can go either way: convert int to MyInt, or convert MyInt to int. Neither option is clearly "better" than the other, so neither of those conversions survive consideration.
Then, having ruled out the closest possible generic version of the method, of the remaining overloads available the only one left is the Equal(string, string) overload (the only other one left with just two parameters is the Equal<T>(IEnumerable<T>, IEnumerable<T>), which is "worse" than the Equal(string, string) overload according to the overload resolution rules). Having found exactly one method that is clearly "better" than any others, the compiler then tries to use that method with your parameters, which of course don't fit, causing the errors to be emitted.
On the other hand…
When you try to call Equal(4, myLong), you've got two incompatible types. A literal having type int, and the MyLong value. In this case, the compiler tries each parameter one by one and finds that when it uses the MyLong type as the type parameter, it is possible to promote the int literal to a long and then implicitly convert that to MyLong. But it can't go the other way. It's not possible to select int as the generic type parameter, because MyLong can't be implicitly converted to int. So in that case, there is a "better" overload to choose, and so it's chosen.
By explicitly specifying the literal's type, you can try different combinations and see this pattern at work. First, I prefer a simpler wrapper class to test with:
public class Wrapper<T>
{
public T Value;
public static implicit operator T(Wrapper<T> wrapper) => wrapper.Value;
public static implicit operator Wrapper<T>(T value) => new Wrapper<T> { Value = value };
}
Then try these:
Wrapper<int> w1 = new Wrapper<int> { Value = 4 };
Wrapper<long> w2 = new Wrapper<long> { Value = 4 };
Assert.Equal(4, w1); // error
Assert.Equal((short)4, w1); // no error
Assert.Equal(4, w2); // no error
Assert.Equal(4L, w2); // error
The only thing that makes int special is that that's the default type for the numeric literal. Otherwise, a type that wraps int works exactly the same as a type that wraps anything else. As long as a conversion is available only in one direction between the two parameters, everything's fine. But when the conversion is available in both directions, the compiler has no choice but to throw up its hands and give up.

Is there any way to implicitly construct a type in C#?

I read of a useful trick about how you can avoid using the wrong domain data in your code by creating a data type for each domain type you're using. By doing this the compiler will prevent you from accidentally mixing your types.
For example, defining these:
public struct Meter
{
public int Value;
public Meter(int value)
{
this.Value = value;
}
}
public struct Second
{
public int Value;
public Second(int value)
{
this.Value = value;
}
}
allows me to not mix up meters and seconds because they're separate data types. This is great and I can see how useful it can be. I'm aware you'd still need to define operator overloads to handle any kind of arithmetic with these types, but I'm leaving that out for simplicity.
The problem I'm having with this approach is that in order to use these types I need to use the full constructor every time, like this:
Meter distance = new Meter(5);
Is there any way in C# I can use the same mode of construction that a System.Int32 uses, like this:
Meter distance = 5;
I tried creating an implicit conversion but it seems this would need to be part of the Int32 type, not my custom types. I can't add an Extension Method to Int32 because it would need to be static, so is there any way to do this?
You can specify an implicit conversion directly in the structs themselves.
public struct Meter
{
public int Value;
public Meter(int value)
{
this.Value = value;
}
public static implicit operator Meter(int a)
{
return new Meter(a);
}
}
public struct Second
{
public int Value;
public Second(int value)
{
this.Value = value;
}
public static implicit operator Second(int a)
{
return new Second(a);
}
}

How to use Double? nullable type with Math.Round in .NET

I want to do something like this but C# doesn't accept this:
public static void setPrice(Double? value)
{
if (value != null) {
this.TextBoxPrice.Text = Math.Round(value, 2).ToString();
} else {
this.TextBoxPrice.Text = "No Price";
}
}
So does it mean using nullable type Double? is completely useless in this use case ? What can I use then ?
Update: I made a mystypo I actually meant
public static void setPrice(Double? value)
so I corrected.
You're not currently using a nullable type - Double is a non-nullable value type, so can never be null. This is what you want:
public static void setPrice(Double? value)
{
if (value != null) {
this.TextBoxPrice.Text = Math.Round(value.Value, 2).ToString();
} else {
this.TextBoxPrice.Text = "No Price";
}
}
On the other hand, you should not be using a double to represent financial values. It's inappropriate as a binary floating point type. Use decimal (or decimal?) instead.
(Note that Double? is equivalent to Nullable<Double>.)
If you've come from a Java background, you may be expecting Double to be a reference "wrapper" type to start with - it's not. In C# double is simply an alias for System.Double; they're the same type.
Jon's answer is fine -- pay particular attention to the bit about decimal -- but I thought I'd add that you can "lift" methods to nullable using higher-order programming. For example:
public static Func<T?, T?> Lift<T>(Func<T, T> func) where T : struct
{
return (T? t)=>t.HasValue ? (T?)func(t.Value) : (T?)null;
}
public static Func<A?, R> LiftRef<A, R>(Func<A, R> func) where A : struct where R : class
{
return (A? a)=>a.HasValue ? func(a.Value) : null;
}
And now you can say:
Func<decimal, decimal> round2 = x=>Math.Round(x, 2);
Func<decimal?, decimal?> liftedRound2 = Lift(round2);
Func<decimal?, string> liftedToString = LiftRef(decimal.ToString);
...
public static void SetPrice(decimal? value)
{
this.TextBoxPrice.Text == liftedToString(liftedRound2(value)) ?? "No Price";
}
I agree with Jon Skeet's answer and just wanted to add that in that specific case you might consider simply adding a ClearPrice method - for reasons of clearer API + avoiding the if-else.

overload operator = in C#. How can i accept other types?

So a friend was telling me how a game was hacked and how the technique worked. He then asked whats the best way to prevent that kind of attack. The most straight forward way i knew was to A) the shuffle the bits of important value B) hash the values and compare them every time (an int that holds the score or money is likely to be checked rarely).
Then i tried the implementation in C#, i couldnt overload the = operator. How can i do this?
ex code.
class EncryptVal <T>
{
T v;
public T operator = (T v2)
{
//shuffle bits
}
public T operator ()()
{
//return unshuffle bits
}
}
You're looking for the implicit and explicit operator, rather than saying =. This allows you to define how things will work when cast implicitly (ie, just an assignment) and explicitly (ie, there's a casting operator).
public static implicit operator Type1(Type2 p) {}
public static explicit operator Type1(Type2 p) {}
You can encapsulate the value in the class and overload the implicit conversions to and from the class:
public class EncryptVal<T> {
private T _value;
private EncryptVal(T value) {
_value = value;
}
public static implicit operator EncryptVal<T>(T value) {
//shuffle bits
return new EncryptVal<T>(value);
}
public static implicit operator T(EncryptVal<T> value) {
//unshuffle bits
return value._value;
}
}
Usage:
// implicit conversion from int
EncryptVal<int> e = 42;
// implicit conversion to int
int i = e;
You are not allowed to overload the assignment operator in C#. Here's the MSDN documentation on it.
You'll have to create your own function for this behavior.
I assume that you come from C++ where it is very common to write classes that are used like primitive data types. In C# you do things more explicitly.
I would write it as a property or as two methods, eg:
class EncryptVal <T>
{
T v;
public T Value
{
get
{
//return unshuffle bits
}
set
{
//shuffle bits
}
}
}
Dont use = for setting the value. You cant overload assignment.
What you can do is hide it behind a property.
int _encyptedValue;
Public int myInt
{
get
{
return Decrypt(_encryptedValue);
}
set
{
_encryptedValue = Encrypt(value);
}
}
You get to chosse your decryption/encryption
I would go the for implicit/explicit operator overloading for the implementation part.
Probably the explicit one since your conversion does heavy processing, and that it eventually could fail.
I would just add that shuffling bits seems to be only an obfuscation technic that will surely not last long if you have wishfull hackers interested in your game.
You probably need stronger cryptography to protect your data, but more context is needed.

Categories