Nullable type as a generic parameter - c#

I'm trying to implement a class that stores a generic nullable type:
public class myclass<T?>
{
T? myvariable;
public T? myfunction(){
return myvariable;
}
}
And while the above class compiles just fine, the actual use that provides trouble:
myclass<int?> c = new myclass<int>();
int? = c.myfunction(); // does not work: implicit cast from type T? in int? not possible.
// or, assuming the variable is not null
int = c.myfunction().Value; // implicit cast from type T in int not possible.
What am I doing wrong or how can I work around this?

Neither of the examples compile:
<T?> isn't valid syntax; it should be <T>
myclass needs a where T : struct constraint
The first line of your second example should read: myclass<int> c = new myclass<int>();.
The rest of your second example should compile OK, however.

Related

Why must nullable primitives be casted as non null before returning from method in C#, yet complex objects do not?

I came across an interesting facet of the C# language this morning I have not experienced yet; consider the below code snippet:
public class Example
{
public int getInt()
{
int? myInt = 2;
return myInt; // <-- compiler error.
}
public object getObject()
{
object? obj = new { };
return obj; // <-- OK, no error.
}
}
The compiler returns an error on the commented line above:Error CS0266: Cannot implicitly convert type 'int?' to 'int'. An explicit conversion exists (are you missing a cast?) (CS0266)
What I find interesting is that the object example works just fine without complaining. I am assuming this is something to do with primitives vs. objects but I am unable to find any resources. I am aware the return type is not matching the object type, I just thought it was curious that it works with objects and not a primitive. If anyone could share some links/provide an explanation as to why this is, it would be greatly appreciated.
int? is syntactic sugar for Nullable<int>, a generic type that is distinct from just plain int. Thus, you can't return a Nullable<int> in a method specified to return int.
object, like other reference types, is nullable by itself and doesn't need to be wrapped in Nullable<T>, and thus can match the return type of getObject() and be returned without error.
Similar to Chris' answer except the nullable object part.
The ? is just syntax sugar for the Nullable<T> generic type. This type implicitly inherits the type object. Because Nullable<T> inherits object, the nullable object can be returned as type object.
The Nullable<T> does not inherit int and therefore cannot be returned with a return type of int.
Here's whats actually going on
public class Example
{
public int getInt()
{
Nullable<int> myInt = 2;
return myInt; // <-- compiler error.
}
public object getObject()
{
Nullable<object> obj = new { };
return obj; // <-- OK, no error.
}
}
When you call this getInt() you are asking for an int, not for an int?. In this way, you can do this:
public int getInt()
{
int? myInt = 2;
if (myInt.HasValue)
{
return myInt.Value; // You must return .Value (int value)
}
else
{
/* You can dou something here, like change to default value and then return 'myInt.Value', p.e.*/
}
}
Anyway, you can use .HasValue to know if a nullable attribute is null or not, and return the non-null value with .Value.
In the other way, when you ask for getObject(), you expect an object, wich can be any kind of type. This is why you have no errors on there.

Casting T from and to Generic<T> (C#)

So I have a generic class, with Type as its generic parameter. In this class is a method, which has object parameter called value. Kinda like this:
public class Foo<Type> where Type : IComparable
{
public void Bar(object value)
{
DoSomething((Type)value);
}
}
As you can notice, I need to "DoSomething" with value (stored in object) that I first need to cast to Type. I even have my own overridden cast, which works on its own.
In this specific case, Type is generic, lets call it GenericType, and has this user-defined cast:
public static implicit operator GenericType<T>(T value)
{
return new GenericType<T>(value);
}
and value is an enum, lets say
public enum Number: short
{
Zero = 0,
One = 1,
Two = 2
}
The 'DoSomething((Type)value)' in this case is where Type is GenericType and value is Number.Zero. For some reason, this causes the cast to throw InvalidCastException: Specified cast is not valid. When I try it directly, i mean like..
GenericType<Number> z = (GenericType<Number>)Number.Zero;
..it works (I know, there is not explicit cast even needed). But for some reason, it does not work in the complex example I stated above. Can anyone help me understand and potentially fix that?
Why not just let your class use the generic type?
public class Foo<T> where T : IComparable
{
public void Bar(T value)
{
DoSomething(value);
}
}
No casting needed... and please don't use reserved words to name stuff.

C# Class as one Value in Class // Mimic int behaviour

Is there a way to make my new Class mimic the behavior of an int or any Valuetype?
I want something, so these assignments are valid
MyClass myClass = 1;
int i = myClass;
var x = myClass; // And here is important that x is of type int!
The MyClass looks roughly like this
public class MyClass {
public int Value{get;set;}
public int AnotherValue{get;set;}
public T GetSomething<T>() {..}
}
Every assignment of MyClass should return the Variable Value as Type int.
So far i found implicit operator int and implicit operator MyClass (int value). But this is not 'good enough'.
I want that MyClass realy behaves like an int. So var i = myClass lets i be an int.
Is this even possible?
If you´d created a cast from your class to int as this:
public static implicit operator int(MyClass instance) { return instance.Value; }
you could implicetly cast an instance of MyClass to an int:
int i = myClass;
However you can not expect the var-keyword to guess that you actually mean typeof int instead of MyClass, so this does not work:
var x = myClass; // x will never be of type int
Apart from this I would highly discourage from an implicit cast as both types don´t have anything in common. Make it explicit instead:
int i = (int) myClass;
See this excellent answer from Marc Gravell for why using an explicit cast over an implicit one. Basically it´s about determing if data will be lost when converting the one in the other. In your case you´re losing any information about AnotherValue, as the result is just a primitive int. When using an explicit cast on the other hand you claim: the types can be converted, however we may lose information of the original object and won´t care for that.
Is this even possible?
No.
You can convert and cast types to other types implicitly and explicitly, but to have one type supersede another type without any inheritance or interface implementation flies in the face of object-oriented programming principles.
The var keyword is a convenience that tries to guess the type of a value with as much precision as possible. Therefore it can't be forced to represent int when the type is MyClass.
You might consider something like this: var x = (int) myClass;

Dynamic Property Assignment Throws RuntimeBinderException

I am getting a RuntimeBinderException with the message
Cannot implicitly convert type 'object' to 'MyNamespace.SomeEnum?'. An explicit conversion exists (are you missing a cast?)
The following code generates that error:
public enum SomeEnum
{
Val1
}
public class Example
{
public SomeEnum? EnumMember { get; set; }
}
public static class Program
{
static void Main()
{
dynamic example = new Example();
// Works without issue
example.EnumMember = (dynamic)Enum.Parse(typeof(SomeEnum), "Val1");
// Works without issue
example.EnumMember = Enum.Parse(example.EnumMember.GetType(), "Val1");
// Throws the aforementioned RuntimeBinderException
example.EnumMember = Enum.Parse(typeof(SomeEnum), "Val1");
}
}
Why do to first two lines work (both return type dynamic), but the third throws an exception (when the return type is object)? I was under the impression that, when assigning to dynamic, the binding is performed using the actual, run-time type of the right-hand-side. Can someone please enlighten me as to why the third line is unable to run as written?
The compile-time type of the expression on the RHS of the = operator for the first two lines is dynamic. In the first case that's because you've cast to dynamic, and in the second case it's because you're using a dynamic value in one of the arguments.
In the third case, the compile-time type of the expression is object. So you're trying to do the equivalent of:
object x = Enum.Parse(typeof(SomeEnum), "Val1");
example.EnumMember = x;
That doesn't work, because there's no implicit conversion from object to SomeEnum?, which is what the compiler is trying to find at execution time.
Note that the nullability part really isn't relevant here - nor is the fact that it's an enum. It's just that the assignment operator is being bound dynamically, but using the compile-time time of the RHS. Here's a similar but simpler example:
class Test
{
public int Foo { get; set; }
static void Main()
{
dynamic example = new Test();
example.Foo = 10; // Fine
object o = 10;
example.Foo = o; // Bang
}
}
If you want the compiler to handle the assignment dynamically using the actual type of the value returned rather than the compile-time type, then using dynamic is exactly what you want to do - either cast to dynamic, or use:
dynamic value = ...;
target.SomeProperty = value;
You still need to do an implicit conversion for the third line
example.EnumMember = (SomeEnum) Enum.Parse(typeof(SomeEnum), "Val1");
EDIT
The reason that you still need implicit conversion is because Enum.Parse returns an object. Refer to the documentation below.
https://msdn.microsoft.com/en-us/library/essfb559(v=vs.110).aspx

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);
}

Categories