Home > OS >  Override abstract method as nullable both reference and value type
Override abstract method as nullable both reference and value type

Time:04-03

I use C# 10 and I have an generic abstract class. This abstract class implemented by 2 other classes which one uses reference type and the other uses value type.

public abstract class BaseClass<T> {
    public abstract T? AbstractNullableTestMethod();
    public abstract T AbstractNotNullableTestMethod();
}

public class A : BaseClass<int> {
    public override int AbstractNotNullableTestMethod() => throw new NotImplementedException();
    public override int? AbstractNullableTestMethod() => throw new NotImplementedException();
}
public class B : BaseClass<string> {
    public override string AbstractNotNullableTestMethod() => throw new NotImplementedException();
    public override string? AbstractNullableTestMethod() => throw new NotImplementedException();
}

In this example, I get an error for class A. Because int is not null so I get return type must be int error for AbstractNullableTestMethod method. If I add where T : struct constraint this time class B get error because string is reference type.

The abstract class has multiple method, some of nullable, the others not. However, it can be implemented by reference type and value type generics.

CodePudding user response:

I can't provide you the answer you're looking for, but I can try to explain why it's not possible.

The ability to add these annotations (e.g. T?) was added in C# 9, the feature was called unconstrained type parameter annotations. The key points:

  • If a type parameter T is substituted with a reference type, then T? represents a nullable instance of that reference type.
  • If T is substituted with a value type, then T? represents an instance of T

The linked design meeting notes highlights the problem here, it's that there are now two different meanings for T? depending on whether T is constrained or not:

  • unconstrained, it means 'the type of default(T)' (so where T is int, T? is also int)
  • constrained to struct it means Nullable<T> (so int?)

They proposed two options to solve this problem, and the one they went with was evidently 'Live with problem 1, and try to explain things as best we can.'

CodePudding user response:

Just remove the question mark in the override method.

public override int AbstractNullableTestMethod() => throw new NotImplementedException();

You may know that in C# int? is short for Nullable<int> which is still a value type, but string? is equivalent to string. so if you wanna declare a method that returns a nullable value type, the type parameter declaration should be:

public class A : BaseClass<int?> {
    public override int? AbstractNotNullableTestMethod() => throw new NotImplementedException();
    public override int? AbstractNullableTestMethod() => throw new NotImplementedException();
}

CodePudding user response:

Hint :- Since one type is null and another non null , you can use two generic type parameters. Please try.

public abstract class BaseClass<T, Tnullable>
{
  public abstract Tnullable? AbstractNullableTestMethod();
  public abstract T AbstractNotNullableTestMethod();
}

public class A : BaseClass<int, int?>
{
  public override int AbstractNotNullableTestMethod() => throw new NotImplementedException();
  public override int? AbstractNullableTestMethod() => throw new NotImplementedException();

}

public class B : BaseClass<string, string?>
{
  public override string AbstractNotNullableTestMethod() => throw new NotImplementedException();
  public override string? AbstractNullableTestMethod() => throw new NotImplementedException();

} 

If above implementation is not allowed in your project you have to adjust your base class. Note that a non reference type can't be nullable and non nullable at the same context. Please find below code snippet.

public abstract class BaseClass<T>
{
  public virtual T? AbstractNullableTestMethod()
  {
    throw new NotImplementedException();
  }
  public abstract T AbstractNotNullableTestMethod();
}

public class A : BaseClass<int>
{
  public override int AbstractNotNullableTestMethod() => throw new NotImplementedException();

}

public class C : BaseClass<int?>
{
  public override int? AbstractNotNullableTestMethod() => throw new NotImplementedException();
  
}

public class B : BaseClass<string>
{
  public override string AbstractNotNullableTestMethod() => throw new NotImplementedException();
  public override string? AbstractNullableTestMethod() => throw new NotImplementedException();

} 
  • Related