C# 通用,具有 notnull 和 nullable 字段

问题描述 投票:0回答:1

我需要为整个项目中的常规树提供一个类。有时树与字符串键一起使用,有时与 Guid 键一起使用。 该类不应具有 null Id 和可为 null 的 ParentId。

  1. 如果我使用这个类:
public class TreeNode<TKey> 
{
    public TKey Id { get; set; }
    public string Name { get; set; }
    public TKey? ParentId { get; set; }
}

1.a. TKey = 指南。当尝试将 null 值分配给 ParentId 时,出现错误“CS0037:无法将 null 转换为“类型”,因为它是不可为 null 的值类型”。

1.b. TKey = 字符串。字符串键没有问题。

  1. 如果我添加
    where TKey: struct
public class TreeNode<TKey> where TKey : struct
{
    public TKey Id { get; set; }
    public string Name { get; set; }
    public TKey? ParentId { get; set; }
}

2.a. TKey = 指南。没有任何错误。

2.b. TKey = 字符串。我遇到错误“CS0453:类型‘类型名称’必须是不可为 null 的值类型,才能将其用作泛型类型或方法‘通用标识符’中的参数‘参数名称’”。

如何修改类以便可以使用两种类型的密钥?

c# generics inheritance tree
1个回答
0
投票

主要问题是

Guid
是值类型,而
string
是引用类型。 当我们创造性地对其应用约束时,拥有值或引用类型的通用参数并没有给我们很大的操作空间(docs)。

我可以给你的解决方案是声明一个封装引用类型的结构泛型类型,如下所示:

public struct StructOf<TClass>
where TClass : class {
    public TClass Instance;
    public StructOf(TClass instance) => Instance = instance;
    public static implicit operator StructOf<TClass>(TClass s) => new StructOf<TClass>(s);
    public static implicit operator TClass(StructOf<TClass> s) => s.Instance;
    public override string ToString() {
        return this.Instance.ToString();
    }
    // TODO: override Equals, GetHashCode etc., ==, !=
}

现在,您的原始泛型类型可以像这样受到约束:

public class TreeNode<TKey>
where TKey : struct {
    public TKey Id { get; set; }
    public string Name { get; set; }
    public TKey? ParentId { get; set; }
}

因此示例用法将是这样的(通过重载隐式运算符使操作变得更简单)

StructOf<string> foo = "foo"; // possible via implicit operator overload
Console.WriteLine(foo); // foo
string bar = foo; // possible via implicit operator overload
Console.WriteLine(bar); // foo

TreeNode<StructOf<string>> treeNode = new();
treeNode.Id = "foo"; // again implicit operator
treeNode.ParentId = null;

TreeNode<Guid> baz = new ();
baz.Id = new Guid();
baz.ParentId = null;
© www.soinside.com 2019 - 2024. All rights reserved.