简体   繁体   中英

Interface passing int or string as generic type and using in nullable and not nullable properties

I'm trying to do a Interface for property changes in a product. In some case the values are int others the values would by string . The new value is required, but sometimes the field don't have a old value.

Something like this:

public interface IChangeSuggestion<TValue> {
    TValue? OldValue { get; set; } //Line with error
    TValue NewValue { get; set; }
}

public class ChangeSuggestionSomeId : IChangeSuggestion<int> {
    public int? OldValue { get; set; }
    public int NewValue { get; set; }
}

public class ChangeSuggestionName : IChangeSuggestion<string> {
    public string OldValue { get; set; }
    public string NewValue { get; set; }
}

the code above throw the error: 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.

Edit

I'm using the interface because a shared approval logic, and the classes are Models for the Entity Framework

To make work in the Entity Framework the follow code do the trick:

public interface IChangeSuggestion<TValue> {
    TValue OldValue { get; set; }
    [Required]
    TValue NewValue { get; set; }
    
    int Id { get; set; }
    int ProductId { get; set; }
    bool? Approved { get; set; }
    DateTime? ApprovedOn { get; set; }
    string ApprovedById { get; set; }
}

public class ChangeSuggestionSomeId : IChangeSuggestion<int?> {
    public int? OldValue { get; set; }
    [Required]
    public int? NewValue { get; set; }

    public int Id { get; set; }
    public int ProductId { get; set; }
    public bool? Approved { get; set; }
    public DateTime? ApprovedOn { get; set; }
    public string ApprovedById { get; set; }
}

This works because i'm using Entity Framework that run a validate on SaveChanges, but i think that strictly NewValue should be a int not a int?

If you can make sure the TValue just would be int , bool , or other value types, you can use where TValue: struct . Or where TValue: class for just reference types.

public interface ChangeSuggestion<TValue> where TValue : struct
{
    TValue? OldValue { get; set; }
    TValue NewValue { get; set; }
}

Otherwise, you can only use two interfaces with different names (one for value type, one for reference type). Or use another more complex solution.

Here's my guess.

I assume you know about there's two kind of types including value type (struct) and reference type.
I think what you really want to ask is now that C# support nullable value type, why we can't use TValue? , I think that's because, in theory, value type variable which points to the stack can't be null, but sometimes we do need it to be nullable. To achieve this, the compiler will make some preprocess during compiling if a value type variable marked as nullable, but a reference type doesn't need this 'preprocess' to be nullable, so we must tell the compiler which type the TValue is then the compiler can decide to do or not do this 'preprocess'.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM