admin管理员组

文章数量:1406052

Is it possible to use C# accessors such as the backing field is nullable but the getter is not ? I want the getter to promise to the rest of the code the value is not null

Since get; set; share the same return type I dont know how to do it. Should I just use separate methods ? It will be awkward to use for the next guy who is used to C# accessors.

public class Foo(DateTime date2)
{
    private DateTime? _date1;
    public DateTime Date1
    {
        get => _date1 ?? Date2;
        set => _date1 = value;
    }
    public DateTime Date2 { get; } = date2;
}
    
var foo = new Foo(DateTime.Now)
{
    Date1 = DateTime.Now.AddDays(1)
};
foo.Date1 = null; // doesnt compile

Is it possible to use C# accessors such as the backing field is nullable but the getter is not ? I want the getter to promise to the rest of the code the value is not null

Since get; set; share the same return type I dont know how to do it. Should I just use separate methods ? It will be awkward to use for the next guy who is used to C# accessors.

public class Foo(DateTime date2)
{
    private DateTime? _date1;
    public DateTime Date1
    {
        get => _date1 ?? Date2;
        set => _date1 = value;
    }
    public DateTime Date2 { get; } = date2;
}
    
var foo = new Foo(DateTime.Now)
{
    Date1 = DateTime.Now.AddDays(1)
};
foo.Date1 = null; // doesnt compile
Share Improve this question asked Mar 6 at 15:32 CalimeroCalimero 3192 silver badges15 bronze badges 8
  • That sounds really weird. What do you expect the getter to return when you set the value to null? It seems pretty akward and creates very much frustration, to see foo.Date1 = null and afterwards notice that foo.Date1 is not null. – MakePeaceGreatAgain Commented Mar 6 at 15:37
  • If this had been a reference type, you could have used the [AllowNull] attribute (my answer here), but I don't think this is possible for a value type like DateTime. – Sweeper Commented Mar 6 at 15:45
  • I really think what you are looking for is a different abstraction. It sounds like you want a DateTime that is never null but can convey the notion of "has not yet been set", correct? – Fildor Commented Mar 6 at 15:46
  • @Sweeper that doesn't solve the actual semantical problem, which is Console.WriteLine(foo.MyProperty = null) printing SomeOtherValue instead of null, which is different from what I would expect to happen at least... – MakePeaceGreatAgain Commented Mar 6 at 15:47
  • 1 @Sweeper sure it is, but it just cries for the next bug to happen and is a really bad idea, IMHO – MakePeaceGreatAgain Commented Mar 6 at 15:50
 |  Show 3 more comments

4 Answers 4

Reset to default 1

You can add [NotNull] to a nullable-typed property.

private DateTime? _date1;
[NotNull]
public DateTime? Date1
{
    get => _date1 ?? Date2;
    set => _date1 = value;
}

// or in newer versions:

[NotNull]
public DateTime? Date1
{
    get => field ?? Date2;
    set;
}

This allows Date1 = null. The type of Date1 is still Nullable<DateTime>, so when you access properties of Date1, you need access them through Value, e.g.

Console.WriteLine(someFoo.Date1.Value.Hour);

Because of [NotNull], the compiler will not emit any warnings when you try to access Value.

Since it is a non nullable property you will never be able to asign null. What you can do is create a ReesetDate method that sets _date1 to null if that would ever be needed.

_date1 will be null by default if there is no value asigned to it in the constructor so i dont see why you would want to reset it to null.

get and set of a property must be of the same type, so either both are DateTime or both are DateTime?. You can override the compiler behaviour with a [NotNull] annotation. But actually I see a semantic problem in your approach, if I set Date1 = null, I'd not expect it to return a non-null value the next time I use it.

I personally would prefer something like the following: Make Date1 a nullable DateTime?, its getter returning _date1 only and make an additional property that returns the fallback of Date2 if necessary

public DateTime? Date1 {get;set;} = null;
public DateTime Date2 { get; } = date2;
public DateTime NonNullDate { get => _date1 ?? Date2; }

You can decorate the property with the [NotNull] attribute, meaning that the return value is never null:

private string _back = string.Empty;

[System.Diagnostics.CodeAnalysis.NotNull]
public string? MyProp
{
    get { return _back; }   
    set { _back = value ?? string.Empty; }
}

This will not complain about "possible null value" when reading the property, but allows writing null to it.

    Console.WriteLine(MyProp.Length);
    MyProp = null;
    Console.WriteLine(MyProp.Length);

writes '0' two times.

See Attributes for null-state static analysis interpreted by the C# compiler

You can also do this with a DateTime? property. However, the return type then remains Nullable<DateTime>, so you need to use .Value to get at its DateTime value.

本文标签: C Getter non nullable but setter nullableStack Overflow