Implicit conversion Must be used Explicitly - c#

I have a struct with the following operator declared :
public struct myStruct {
public static implicit operator int(Nullable<myStruct> m){
/*...*/
}
}
This operator alone lets me implicitly convert a non-nullable struct to int, but trying to implicitly convert its nullable counterpart still raises a compilation error :
Cannot implicitly convert type myStruct? to int. An explicit
conversion exists (are you missing a cast?)
Apparently the mentioned "explicit" operator is actually the implicit operator I declared, removing this operator altogether also removes the mention of the explicit one.
When it comes to nullable structs, why am I being forced to use this operator explicitly even though it was declared implicit?
EDIT:
So here is the "full code", stripped of everything that doesn't make the compiler error disappear. The struct stays literally the same, all that's new is my testing code :
using System;
public struct boilDown {
public static implicit operator int(Nullable<boilDown> s) { return 0; }
} // END Struct
public class Sandbox {
void Update ()
{
boilDown nonNullable = new boilDown ();
Nullable<boilDown> NullableVersion = new Nullable<boilDown>();
int MyInt;
MyInt = nonNullable; // this work thanks to my operator
MyInt = NullableVersion; // But this line requires an explicit cast
}
}
VERSION :
You all hinted me at a c# version issue.
I'm working on Unity 2017.1.0f3, which rather than .Net, uses Mono 2.0.50727.1433. (This apparently is a NET3.5 Equivalent, but even their experimental NET4.6 equivalent has this issue.)
I'll ask this question to them and see what they say.

You could explicitly cast the NullableVersion to int like below.
using System;
public struct boilDown {
public static implicit operator int(Nullable<boilDown> s) { return 0; }
} // END Struct
public class Sandbox {
static void Main()
{
}
void Update ()
{
boilDown nonNullable = new boilDown ();
Nullable<boilDown> NullableVersion = new Nullable<boilDown>();
int MyInt;
MyInt = nonNullable; // this work thanks to my operator
MyInt = (int)NullableVersion; // works now
}
}

Thanks all who told me this code should compile.
Unity confirmed this error to be a bug on their end.

Related

Why does Mathf.Abs(MyClass v) call an implicit int conversion rather than an implicit float conversion in C#?

I'm using dynamic types and implicit conversions and am curious why the following code calls the implicit int conversion and not the implicit float conversion within my TestClass?
TestClass myVar = 1.6f;
var result = Mathf.Abs(myVar);
The value assigned from this code is essentially Mathf.Abs(1) rather than Mathf.Abs(1.6f).
For reference, the following is my TestClass which is a contrived class for the purpose of this post.
class TestClass
{
public dynamic variable;
TestClass(dynamic v)
{
variable = v;
}
public static implicit operator float(TestClass v)
{
return (float)v.variable;
}
public static implicit operator int(TestClass v)
{
return (int)v.variable;
}
public static implicit operator TestClass(float v)
{
return new TestClass(v);
}
}
Ultimately I'm creating a class to mirror the functionality of another language which allows variables to be float, string or boolean (without specifically declaring the type) and casts appropriately at run-time depending on the operator or function to which they're being applied. The language in question is one designed to help children learn to code and handles any situation gracefully without crashing. This information isn't really required for the question but gives a general overview of the background.
Firstly, we can reproduce this without needing Unity or dynamic typing. The following example prints 1, calling the PrintValue(int) overloads:
using System;
public class Wrapper
{
private float value;
public Wrapper(float value) => this.value = value;
public static implicit operator float(Wrapper wrapper) =>
wrapper.value;
public static implicit operator int(Wrapper wrapper) =>
(int) wrapper.value;
}
class Test
{
static void Main()
{
Wrapper wrapper = new Wrapper(1.5f);
PrintValue(wrapper);
}
static void PrintValue(float f) => Console.WriteLine(f);
static void PrintValue(int i) => Console.WriteLine(i);
}
The rules of overload resolution are described in the ECMA language specification section 12.6.4. Both overloads of PrintValue are applicable function members because there's an implicit conversion from Wrapper to each of float and int.
In this case, PrintValue(int) ends up as the better function member because the conversion from Wrapper to int is a better conversion from expression than the conversion from Wrapper to float (12.6.4.4) because int is a better conversion target than float (12.6.4.6) because there's an implicit conversion from int to float, but there isn't an implicit conversion from float to int.
To put it another way: int is a sort of "more specific" parameter type than float, in the same way that string would be a "more specific" parameter than object. (Because of the implicit conversions available.)

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.

Combination of implicit conversion, equality operator and nullables fails to compile after update from Visual Studio 2015.2 to 2015.3

Below code compiles in VS2015.2, but after upgrade to VS2015.3 it fails with error CS0019: Operator '==' cannot be applied to operands of type 'Registration<Something>' and 'Something'.
public class Class1
{
public Class1()
{
var a = new Registration<Something>();
var x = a == Something.Bad; // this line fails in VS2015.3
}
}
public struct Registration<T> where T:struct
{
public static implicit operator T?(Registration<T> registration)
{
return null;
}
}
public enum Something
{
Good,
Bad
}
I can not find any notice about such a change in the changelog for update 3. Can someone tell me, why this happens? And which is the correct behavior?
EDIT: Combination of implicit conversion, equality operator and nullables... and enums. This only seems to fail when T is an enum.
Looks like a bug. We're tracking this as https://github.com/dotnet/roslyn/issues/13380

Why can't I cast one instantiation of a generic type to another?

How can I implement a struct so that the following cast can be performed?
var a = new StatusedValue<double>(1, false);
var b = (StatusedValue<int>)a;
My implementation should behave similarly to Nullable<T>, which works fine. However, this code fails with System.InvalidCastException:
public struct StatusedValue<T> where T : struct
{
public StatusedValue(T value) : this(value, true)
{
}
public StatusedValue(T value, bool isValid)
{
this.value = value;
this.isValid = isValid;
}
private T value;
private bool isValid;
public static implicit operator StatusedValue<T>(T value)
{
return new StatusedValue<T>(value);
}
public static explicit operator T(StatusedValue<T> value)
{
return value.value;
}
}
Result:
Unable to cast object of type 'StatusedValue`1[System.Double]' to type
'StatusedValue`1[System.Int32]'.
This works for Nullable<T> types because they get special treatment from the compiler. This is called a "lifted conversion operator", and you cannot define your own.
From section 6.4.2 of the C# Specification:
6.4.2 Lifted conversion operators
Given a user-defined conversion operator that converts from a non-nullable value type S to a
non-nullable value type T, a lifted conversion operator exists that
converts from S? to T?. This lifted conversion operator performs an
unwrapping from S? to S followed by the user-defined conversion from S
to T followed by a wrapping from T to T?, except that a null valued
S? converts directly to a null valued T?. A lifted conversion operator
has the same implicit or explicit classification as its underlying
user-defined conversion operator. The term “user-defined conversion”
applies to the use of both user-defined and lifted conversion
operators
If you're happy calling a method, try
public StatusedValue<U> CastValue<U>() where U : struct
{
return new StatusedValue<U>((U)Convert.ChangeType(value, typeof(U)), isValid);
}
This will unfortunately throw at runtime rather than compile time if T cannot be converted to U.
Edit: As pointed out below, if you constrain to IConvertible as well as/instead of struct then every conversion is theoretically possible at compile time, and you'll only get a runtime failure because of bad runtime values.
Nullables are specially handled by the compiler, I don't know if this is the case here.
Your operators would allow this:
StatusedValue<int> b = (int)a;
which is probably not what you want, because IsValid is not copied this way.
You could implement an extension method like this:
public static StatusedValue<TTarget> Cast<TSource, TTarget>(this StatusedValue<TSource> source)
where TTarget : struct
where TSource : struct
{
return new StatusedValue<TTarget>(
(TTarget)Convert.ChangeType(
source.Value,
typeof(TTarget)),
source.IsValid);
}
b = a.Cast<int>();
But the compiler cannot check if the types are compatible. ChangeType also returns an object, thus boxing your value.
The answer to why it's like this has already been posted and marked as the answer.
However, you can simplify the syntax to make it easier and clearer to do this while retaining compile-time type-safety.
Firstly, write a helper class to avoid having to specify redundant type parameters:
public static class StatusedValue
{
public static StatusedValue<T> Create<T>(T value, bool isValid = true) where T: struct
{
return new StatusedValue<T>(value, isValid);
}
}
Next you need to expose the underlying value with a Value property (otherwise you can't cast it from code).
Finally you can change your original code from this:
var a = new StatusedValue<double>(1, false);
var b = (StatusedValue<int>)a;
To this:
var a = StatusedValue.Create(1.0, false);
var b = StatusedValue.Create((int)a.Value, false);
where you are doing a simple cast on a.Value.
For a workaround, you will need to provide a way for converting from one underlying type to the other, since the compiler won't be able to figure that out:
public StatusedValue<TResult> To<TResult>(Func<T, TResult> convertFunc)
where TResult : struct {
return new StatusedValue<TResult>(convertFunc(value), isValid);
}
You can then do:
var a = new StatusedValue<double>(1, false);
var b = a.To(Convert.ToInt32);
With some reflection you could build a lookup table of the Convert methods, and lookup the right one based on the type arguments, and then you could default the conversion function to null and if it's not provided, try to lookup the correct conversion automatically. This would remove the clumsy Convert.ToInt32 part, and simply do var b = a.To<int>();
As Rawling points out, Convert.ChangeType can be used. This would make my method look like:
public StatusedValue<T2> To<T2>(Func<T, T2> convertFunc = null)
where T2 : struct {
return new StatusedValue<T2>(
convertFunc == null
? (T2)Convert.ChangeType(value, typeof(T2))
: convertFunc(value),
isValid
);
}
If you don't need a casting, you can add a method like this:
public StatusedValue<int> ConvertToStatusedInt() {
return new StatusedValue<int>(Convert.ToInt32(value), isValid);
}
As suggested in comment:
public StatusedValue<Q> ConvertTo<Q>() where Q:struct {
return new StatusedValue<Q>((Q)Convert.ChangeType(value, typeof(Q)), isValid);
}

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