Need help understanding C# generics - c#

I am self-studying a C# reference and it gives the following information:
1.21.4. Declaring Generic Parameters
Generic parameters can be introduced in the declaration of classes, structs, interfaces, delegates (see the upcoming "Delegates" section), and methods. Other constructs, such as properties, cannot introduce a generic parameter, but can use a generic parameter. For example, the property Value uses T:
public struct Nullable<T>
{
public T Value {get;}
}
First, I get an error trying to compile this saying that it must contain a body because it is neither abstract nor extern or that automatic parameters must have both get and set accessors.
Second, assuming it is wrong and I correct it by adding "set;", I cannot seem to format a call to it successfully.

That is just showing the API of Nullable<T> rather than the implementation. It's not meant to be compiled - System.Nullable<T> is part of the framework, you don't have to implement it yourself.

You appear to be reading "C# 3.0 in a Nutshell". Well, the example is just that - an example. It is only intended to illustrate how the Value property of the Generic Nullable class exposes the generic parameter declared by the containing type.
It isn't meant to be part of a compilable example.

I'm not sure if you just picked a bad example for your struct name (since Nullable is a framework struct), but if not, the error is due to the fact that you have no set accessor in your property. Automatic properties (added in C# 3.0) need both a get and set property. So, if you change the code to:
public struct Nullable<T>
{
public T Value {get; set; }
}
it should work. In this case, the error had nothing to do with generics. To create an instance, you could use:
Nullable<int> i = new Nullable<int>();
This will make it compile. However, as both Jon and Cerebrus has pointed out, it's probably just an example to show the workings of generics.

For an automatic property you always need both a getter and setter. Without a getter you could set the value, but nothing could ever retrieve it. Without a setter the value would always be the default because nothing could ever set it:
//tradition
private T _value;
public T Value
{
get
{
return _value;
}
}
//locally, _value can always be set
//Auto-matically implemented property
public T Value { get; }
//there is never a way to set it
//with this it can be privately set, but is get only to everyone else
public T Value{ get; private set; }

Your question here seems to be about auto-properties, rather than generics.
Auto-properties must have a set accessor, although it doesn't have to have the same visibility as the get:
public T Value { get; private set; }
You can call the set in the constructor:
public Nullable ( T value ) {
Value = value;
}
Although in this case you're dealing with a struct, and they always have a default (parameterless) constructor - you have to be a bit more careful with structs and auto-properties.
In .net there's already a nullable generic:
Nullable<int> i = GetCounterThatMightBeNull();
int j = 0;
if( i.HasValue )
j = i.Value;
...
This was added in .Net 2 (at the same time as generics), and while early betas looked like the code above they streamlined it the final version:
//int? is shorthand for Nullable<int>
int? i = GetCounterThatMightBeNull();
// ?? is shorthand for the null check
int j = i ?? 0;
//or
if( i == null ) {
//this works even though Nullable<int> is a struct
}

Related

What does the part "=> 100" mean in the C# property?

In some article I found this:
public interface ICargo {
int FoodStorage { get => 100; }
}
What does the part => 100 mean?
From the context it looks like a default value. But as I know this is not how the default value is set. At least, I've never seen this kind of syntax in this context.
I've tried googling, it didn't help.
The syntax is called expression-bodied property/member.
It can be used for a read-only propery as demonstrated by your code.
get => 100;
Is equivalent to:
get { return 100; }
But in your specific case there is another issue involved:
Since you use it in an interface, it actually provides a default implementation for the property.
If a class implementing the interface does not provide impelmentation for this property, the default provided by the interface (i.e. have the property retuning 100) will be used.
This is called default interface implementation and it is available from C# 8.0 only.
It is expression bodies property, its short form of writing a property which has only getter and has the constant value.
Its equivalent is
public int FoodStorage
{
get { return 100; }
}
and its read-only property, the expression-bodied property is available from C# 6.0
It's an expression bodied element basically it would behave the same as
public interface ICargo
{
int FoodStorage { get { return 100; }
}
Making use of a lambda expression can make the code cleaner without the excess brackets. You can use both syntax wherever you can use properties.

Nullable reference types: How to specify "T?" type without constraining to class or struct

I want to create a generic class that has a member of type T. T may be a class, a nullable class, a struct, or a nullable struct. So basically anything. This is a simplified example that shows my problem:
#nullable enable
class Box<T> {
public T Value { get; }
public Box(T value) {
Value = value;
}
public static Box<T> CreateDefault()
=> new Box<T>(default(T));
}
Due to using the new #nullable enable feature I get the following warning: Program.cs(11,23): warning CS8653: A default expression introduces a null value when 'T' is a non-nullable reference type.
This warning makes sense to me. I then tried to fix it by adding a ? to the property and constructor parameter:
#nullable enable
class Box<T> {
public T? Value { get; }
public Box(T? value) {
Value = value;
}
public static Box<T> CreateDefault()
=> new Box<T>(default(T));
}
But now I get two errors instead:
Program.cs(4,12): error CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type. Consider adding a 'class', 'struct', or type constraint.
Program.cs(6,16): error CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type. Consider adding a 'class', 'struct', or type constraint.
However, I don't want to add a constraint. I don't care if T is a class or a struct.
An obvious solution is to wrap the offending members under a #nullable disable directive. However, like #pragma warning disable, I'd like to avoid doing that unless it's necessary. Is there another way in getting my code to compile without disabling the nullability checks or the CS8653 warning?
$ dotnet --info
.NET Core SDK (reflecting any global.json):
Version: 3.0.100-preview4-011223
Commit: 118dd862c8
What to do if you are using C# 9
In C# 9, you can use T? on an unconstrained type parameter to indicate that the type is always nullable when T is a reference type. In fact, the example in the original question "just works" after adding ? to the property and constructor parameter. See the following example to understand what behaviors you may expect for different kinds of type arguments to Box<T>.
var box1 = Box<string>.CreateDefault();
// warning: box1.Value may be null
box1.Value.ToString();
var box2 = Box<string?>.CreateDefault();
// warning: box2.Value may be null
box2.Value.ToString();
var box3 = Box<int>.CreateDefault();
// no warning
box3.Value.ToString();
var box4 = Box<int?>.CreateDefault();
// warning: 'box4.Value' may be null
box4.Value.Value.ToString();
What to do if you are using C# 8
In C# 8, it is not possible to put a nullable annotation on an unconstrained type parameter (i.e. that is not known to be of a reference type or value type).
As discussed in the comments on this question, you will probably need to take some thought as to whether a Box<string> with a default value is valid or not in a nullable context and potentially adjust your API surface accordingly. Perhaps the type has to be Box<string?> in order for an instance containing a default value to be valid. However, there are scenarios where you will want to specify that properties, method returns or parameters, etc. could still be null even though they have non-nullable reference types. If you are in that category, you will probably want to make use of nullability-related attributes.
The MaybeNull and AllowNull attributes have been introduced to .NET Core 3 to handle this scenario.
Some of the specific behaviors of these attributes are still evolving, but the basic idea is:
[MaybeNull] means that the output of something (reading a field or property, a method return, etc.) could be null.
[AllowNull] means that the input to something (writing a field or property, a method parameter, etc.) could be null.
#nullable enable
using System.Diagnostics.CodeAnalysis;
class Box<T>
{
// We use MaybeNull to indicate null could be returned from the property,
// and AllowNull to indicate that null is allowed to be assigned to the property.
[MaybeNull, AllowNull]
public T Value { get; }
// We use only AllowNull here, because the parameter only represents
// an input, unlike the property which has both input and output
public Box([AllowNull] T value)
{
Value = value;
}
public static Box<T> CreateDefault()
{
return new Box<T>(default);
}
public static void UseStringDefault()
{
var box = Box<string>.CreateDefault();
// Since 'box.Value' is a reference type here, [MaybeNull]
// makes us warn on dereference of it.
_ = box.Value.Length;
}
public static void UseIntDefault()
{
// Since 'box.Value' is a value type here, we don't warn on
// dereference even though the original property has [MaybeNull]
var box = Box<int>.CreateDefault();
_ = box.Value.ToString();
}
}
Please see https://devblogs.microsoft.com/dotnet/try-out-nullable-reference-types for more information, particularly the section "the issue with T?".
Jeff Mercado raised a good point in the comments:
I think you have some conflicting goals here. You want to have the notion of a default box but for reference types, what else is an appropriate default? The default is null for reference types which directly conflicts with using nullable reference types. Perhaps you will need to constrain T to types that could be default constructed instead (new()).
For example, default(T) for T = string would be null, since at runtime there is no distinction between string and string?. This is a current limitation of the language feature.
I have worked around this limation by creating separate CreateDefault methods for each case:
#nullable enable
class Box<T> {
public T Value { get; }
public Box(T value) {
Value = value;
}
}
static class CreateDefaultBox
{
public static Box<T> ValueTypeNotNull<T>() where T : struct
=> new Box<T>(default);
public static Box<T?> ValueTypeNullable<T>() where T : struct
=> new Box<T?>(null);
public static Box<T> ReferenceTypeNotNull<T>() where T : class, new()
=> new Box<T>(new T());
public static Box<T?> ReferenceTypeNullable<T>() where T : class
=> new Box<T?>(null);
}
This seems type safe to me, at the cost of more ugly call sites (CreateDefaultBox.ReferenceTypeNullable<object>() instead of Box<object?>.CreateDefault()). In the example class I posted I'd just remove the methods completely and use the Box constructor directly. Oh well.
class Box<T> {
public T! Value { get; }
public Box(T! value) {
Value = value;
}
public static Box<T> CreateDefault()
=> new default!;
}
What does null! statement mean?

out parameters with nullable reference types

I have implemented an Option type for some project of mine like this:
public abstract Option<T> {}
public class None<T> : Option<T>
public class Some<T> : Option<T>
{
public T Value { get; }
public Some(T value)
{
Value = value;
}
}
For finding out if an Option contains a value I use this extension method which makes use of pattern matching:
public static bool TryGetValue<T>(this Option<T> option, out T value)
{
if (option is Some<T> some)
{
value = some.Value;
return true;
}
value = default;
return false;
}
I now get the following warning for return default;
Cannot convert null literal to non nullable reference or unconstrained type parameter
It is impossible for me to restrict the generic parameter T to class or struct.
For example, if I restricted the generic parameter to class, I couldn't generate Option<int?> instances as the Nullable<int> type is a struct itself. Declaring the out parameter as nullable via postfixing ? is also not a solution as it seems.
To me the type system is somewhat broken or not thoroughly thought through at this stage. Either Nullable should have been a class or there needs to be a generic parameter restriction like:
public static bool TryGetValue<T>(this Option<T> option, out T value)
where T : nullable [...]
Is there another approach that might be suitable for this issue? What am I missing?
Use the MaybeNullWhenAttribute or the NotNullWhenAttribute. I recommend MaybeNullWhen since it works even on a type parameter not constrained to a struct or reference type.
public static bool TryGetValue<T>(this Option<T> option, [MaybeNullWhen(false)] out T value)
{
if (option is Some<T> some)
{
value = some.Value;
return true;
}
value = default;
return false;
}
Usage:
if(option.TryGetValue(out var value))
{
value.SomeMethod(); // no warning - value is known to be non-null here
}
value.SomeMethod(); // warning - value may be null here.
The attribute is not available pre .Net standard 2.1/.new core 3.0, but you can manually define it yourself if it's not available. Make sure it's internal, as otherwise if another library also defines it as public and someone inherits from both libraries it will cause conflicts:
namespace System.Diagnostics.CodeAnalysis
{
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter may be null even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
internal sealed class MaybeNullWhenAttribute : Attribute
{
/// <summary>Initializes the attribute with the specified return value condition.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter may be null.
/// </param>
public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
/// <summary>Gets the return value condition.</summary>
public bool ReturnValue { get; }
}
(taken from https://github.com/dotnet/runtime/blob/6077cf01f951a711a26a8d5970b211b6031b5158/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs#L45-L60)
There is no pretty way to have a completely generic solution as of today with C# 8.0.
[NotNullWhen()] attribute is one step forward, but then we will run into following:
A nullable type parameter must be known to be a value type or non-nullable reference type. Consider adding a 'class', 'struct' or type constraint.
I'd say this is a major pain point with nullables now. I hope it will be addressed in 8.1 or something...
Relevant discussion - https://github.com/dotnet/csharplang/issues/2194 - allow generic methods to specify T? without constraining to class or struct.
As a workaround, multiple extension method copies with required where constraints can be made to cover all possible types.
Since the issue #1628 was fixed, it is now possible to have all overloads in a single extension class. But it still require to double the number of extension methods for every independent generic out parameter. Yikes!
From a quick look, I couldn't find an opened issue specific to the out parameters. Might worth to bring this particular use case to csharplang github issues if that wasn't done yet.
Update: I made a comment in the above-mentioned issue with my take on it.

C# - Calling a struct constructor that has all defaulted parameters

I ran into this issue today when creating a struct to hold a bunch of data. Here is an example:
public struct ExampleStruct
{
public int Value { get; private set; }
public ExampleStruct(int value = 1)
: this()
{
Value = value;
}
}
Looks fine and dandy. The problem is when I try to use this constructor without specifying a value and desiring to use the defaulted value of 1 for the parameter:
private static void Main(string[] args)
{
ExampleStruct example1 = new ExampleStruct();
Console.WriteLine(example1.Value);
}
This code outputs 0 and does not output 1. The reason is that all structs have public parameter-less constructors. So, like how I'm calling this() my explicit constructor, in Main, that same thing occurs where new ExampleStruct() is actually calling ExampleStruct() but not calling ExampleStruct(int value = 1). Since it does that, it uses int's default value of 0 as Value.
To make matters worse, my actual code is checking to see that int value = 1 parameter is within a valid range within the constructor. Add this to the ExampleStruct(int value = 1) constructor above:
if(value < 1 || value > 3)
{
throw new ArgumentException("Value is out of range");
}
So, as it stands right now, the default constructor actually created an object that is invalid in the context I need it for. Anyone know how I can either:
A. Call the ExampleStruct(int value = 1) constructor.
B. Modify how the default values are populated for the ExampleStruct() constructor.
C. Some other suggestion/option.
Also, I am aware that I could use a field like this instead of my Value property:
public readonly int Value;
But my philosophy is to use fields privately unless they are const or static.
Lastly, the reason I'm using a struct instead of a class is because this is simply an object to hold non-mutable data, should be fully populated when it is constructed, and when passed as a parameter, should not be able to be null (since it is passed by value as a struct), which is what struct's are designed for.
Actually, MSDN has some good guidance on struct
Consider defining a structure instead of a class if instances of the
type are small and commonly short-lived or are commonly embedded in
other objects.
Do not define a structure unless the type has all of the following
characteristics:
It logically represents a single value, similar to primitive types
(integer, double, and so on).
It has an instance size smaller than 16 bytes.
It is immutable.
It will not have to be boxed frequently.
Notice that they are considerations for considering a struct, and its never a "this should always be a struct". That is because the choice to use a struct can have performance and usage implications (both positive and negative) and should be chosen carefully.
Notice in particular that they don't recommend struct for things > 16 bytes (then the cost of copying becomes more expensive than copying a reference).
Now, for your case, there is really no good way to do this other than to create a factory to generate a struct for you in a default state or to do some sort of trick in your property to fool it into initializing on first use.
Remember, a struct is supposed to work such that new X() == default(X), that is, a newly constructed struct will contain the default values for all fields of that struct. This is pretty evident, since C# will not let you define a parameterless constructor for a struct, though it is curious that they allow all arguments to be defaulted without a warning.
Thus, I'd actually suggest you stick with a class and make it immutable and just check for null on the methods that it gets passed to.
public class ExampleClass
{
// have property expose the "default" if not yet set
public int Value { get; private set; }
// remove default, doesn't work
public ExampleStruct(int value)
{
Value = value;
}
}
However, if you absolutely must have a struct for other reasons - but please consider the costs of struct such as copy-casts, etc - you could do this:
public struct ExampleStruct
{
private int? _value;
// have property expose the "default" if not yet set
public int Value
{
get { return _value ?? 1; }
}
// remove default, doesn't work
public ExampleStruct(int value)
: this()
{
_value = value;
}
}
Notice that by default, the Nullable<int> will be null (that is, HasValue == false), thus if this is true, we didn't set it yet, and can use the null-coalescing operator to return our default of 1 instead. If we did set it in the constructor, it will be non-null and take that value instead...
I don't think it's good design to have a struct ExampleStruct such that
default(ExampleStruct)
i.e. the value where all instance fields are zero/false/null, is not a valid value of the struct. And as you know, when you say
new ExampleStruct()
that's exactly the same as default(ExampleStruct) and gives you the value of your struct where all fields (including "generated" fields from auto-properties) are zero.
Maybe you could do this:
public struct ExampleStruct
{
readonly int valueMinusOne;
public int Value { get { return valueMinusOne + 1; } }
public ExampleStruct(int value)
{
valueMinusOne = value - 1;
}
}
I guess the compiler is actually picking the automatic default ctor for structs here http://msdn.microsoft.com/en-us/library/aa288208(v=vs.71).aspx, rather than using your ctor with the default values.
added references:
http://csharpindepth.com/Articles/General/Overloading.aspx (Optional parameters section)
Although some languages (CIL if nothing else) will allow one to define a struct constructor such that new T() has fields set to something other than their "all zeroes" defaults, C# and vb.net (and probably most other languages) take the view that since things like array elements and class fields must always be initialized to default(T), and since having them be initialized to something which didn't match new T() would be confusing, structures shouldn't define new T() to mean something other than default(T).
I would suggest that rather than trying to jinx a default parameter in a parameterized constructor, you simply define a static struct property which returns your desired default value, and replace every occurrence of new ExampleStruct() with ExampleStruct.NiceDefault;.
2015 Addendum
It appears that C# and VB.NET may ease the prohibition against defining parameterless struct constructors. This may cause a statement like Dim s = New StructType() to assign s a value which is different from the value given to new array items of type StructType. I'm not terribly keen on the change, given that new StructType is often used in places where something analogous to C#'s default(StructType) would be more appropriate if it existed. VB.NET would allow Dim s As StructType = Nothing, but that seems rather hokey.
why do you have public ExampleStruct(int value = 1) : this() ?
shouldn't it be public ExampleStruct(int value = 1)? I think the :this() is creating the no-parameter constructor.

Create a property that accepts a different type than it returns

I have a public method in a class. I would like to make this private and use a property to expose the method. The problem is that my method accepts an integer parameter and returns a boolean. In my experience a property has to accept and return the same type. What is the best practice to encapsulate this method and expose it using a property?
You shouldn't be using properties this way. Properties are used to wrap get_ and set_ calls to an appropriate backing field and expose them as a single member. The set_ method that is generated internally is void and accepts an instance of the property type as its only argument.
If what you are trying to achieve requires a method, then expose a method. The only solution you could possibly use otherwise would be to use object.
If the value passed in isn't the same as the value returned, then it's not a property. If you go down this route you'll be creating confusion for anyone who needs to call your code, or maintain it in the future.
The only solution I can think of, and a bad one at that, is to declare the property to be of type object.
What is the best practice to encapsulate this method and expose it using a property?
Does it have to be the same property? Could you have something similar to:
private Type2 _valueThatIsStoredAsAResultOfCallMethod;
private Type2 CallMethod(Type1 value)
{
// Whatever logic is required here to take a value of Type1 and
// get a value of Type2 from it
return value.ToType2();
}
public Type1
{
set
{
// value is of type Type1
_valueThatIsStoredAsAResultOfCallMethod = CallMethod(value);
}
}
public Type2
{
get
{
return _valueThatIsStoredAsAResultOfCallMethod;
}
}
public bool MyProp
{
get;
private set;
}
public int MyProp_AsInt
{
set
{
MyProp = (value > 0) ? true : false;
}
}
Your function's body can replace the above 'set'.
I just put some sample code there.
Make sure you assign the return val of your function to MyProp.
full code
public class MyClass
{
public bool MyProp
{
get;
private set;
}
public int MyProp_AsInt
{
set
{
MyProp = (value > 0) ? true : false;
}
}
}
public class Program
{
static void Main(string[] args)
{
MyClass o = new MyClass();
o.MyProp_AsInt = 1;
System.Console.WriteLine("{0}", o.MyProp);
o.MyProp_AsInt = 0;
System.Console.WriteLine("{0}", o.MyProp);
string line = System.Console.ReadLine();
}
}
Well, generally speaking, it's bad practice to call a method via a property (or do anything complicated in a property) as it's not what the user of the class would expect to happen. The expected behaviour being getting a value.
I would just expose the method.
A method that takes a parameter and returns a value doesn't translate well into a property, regardless of the types it uses.
The method accepts the parameter, then returns the result, while a parameter either accepts a value or returns a value, not both in the same operation. If you would have to use the property by first setting the value, then reading the value, that would be very counter intuitive. It's simply not at all how you normally use a property.
There is no best practice for doing this because it's a bad practice.
If you had two covariant types as your accept/return, you could refer to them by their lowest common ancestor, but I'd still be wary.

Categories