【问题标题】:Interface passing int or string as generic type and using in nullable and not nullable properties将 int 或 string 作为泛型类型传递并在可空和不可空属性中使用的接口
【发布时间】:2020-06-25 17:55:30
【问题描述】:

我正在尝试为产品中的属性更改做一个接口。在某些情况下,这些值是 int,而在其他情况下,这些值将是 string。 新值是必需的,但有时该字段没有旧值。

类似这样的:

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

上面的代码抛出错误: 可空类型参数必须已知为值类型或不可空引用类型。考虑添加“类”、“结构”或类型约束。

编辑

我使用该接口是因为共享批准逻辑,并且类是实体框架的模型

要在实体框架中工作,以下代码可以解决问题:

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

这是因为我使用的是在 SaveChanges 上运行验证的实体框架,但我认为严格来说 NewValue 应该是 int 而不是 int?

【问题讨论】:

标签: c# c#-8.0


【解决方案1】:

如果您可以确保TValue 只是intbool 或其他值类型,则可以使用where TValue : struct。或 where TValue : class 仅用于引用类型。

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

否则,您只能使用两个不同名称的接口(一个用于值类型,一个用于引用类型)。或者使用其他更复杂的解决方案。

这是我的猜测。

我假设您知道有两种类型,包括值类型(结构)和引用类型。
我想你真正想问的是现在C#支持可空值类型,为什么我们不能使用TValue?,我认为这是因为理论上指向堆栈的值类型变量不能为空,但是有时我们确实需要它可以为空。为了实现这一点,编译器会在编译过程中进行一些预处理,如果值类型变量标记为可空,但引用类型不需要这个“预处理”可以为空,所以我们必须告诉compiler 类型为 TValuecompiler 可以决定是否执行此“预处理”。

【讨论】:

  • 问题是 int 是一个结构,而 string 是一个类,我的解决方案是 TValue as int?和 NewValue 上的 [Required] 属性...
  • @Diógenes 是的,我忘记了,那么你只能使用两个不同名称的接口(一个用于值类型,一个用于引用类型)。或者其他更复杂的解决方案。
猜你喜欢
  • 1970-01-01
  • 2017-09-25
  • 2010-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-25
  • 2020-10-27
相关资源
最近更新 更多