处理通用树键
本文关键字:处理 | 更新日期: 2023-09-27 18:29:03
我需要处理树的通用接口。例如:
class ITreeNode<TKey>
{
TKey Id {get; set;}
TKey? ParentId {get; set;} // okay for numeric types, but what about strings?
}
class ITreeNode<TKey>
{
TKey Id {get; set;}
TKey ParentId {get; set;} // again okay for strings, but what about numeric types?
}
如果泛型类型参数必须支持基元类型和类(如string
),如何处理属性的类型化?实体是使用实体框架保存到数据库中的,所以我不能做像bool HasParent
(外键)这样的野生操作。
我会通过三个接口来艰难地做到这一点:一个非泛型变体,一个用于基元类型(如int
、bool
等)的泛型,另一个用于其余类型(类)。
部分代码:
interface ITreeNodeNG
{
object Id { get; set; }
object ParentId { get; set; }
}
interface ITreeNodeP<TKey> where TKey : struct
{
TKey? Id { get; set; }
TKey? ParentId { get; set; }
}
interface ITreeNodeC<TKey>
{
TKey Id { get; set; }
TKey ParentId { get; set; }
}
public class X : ITreeNodeP<int>, ITreeNodeNG
{
public int? Id { get; set; }
public int? ParentId { get; set; }
object ITreeNodeNG.Id
{
get
{
return this.Id;
}
set
{
this.Id = (int)value;
}
}
object ITreeNodeNG.ParentId
{
get
{
return this.ParentId;
}
set
{
this.ParentId = (int?)value;
}
}
}
static void Main(string[] args)
{
ITreeNodeNG x = new X();
ITreeNodeP<int> y = new X();
ITreeNodeC<string> z = null; // you know what to do
}
示例类X
实现了非泛型接口和基元接口。这将使您有可能在不知道接口的确切类型的情况下获得ID。如果您愿意,X
类可以是一个(抽象)基类。
我猜你想要类似Maybe<T>
类的东西——它相当于Nullable<T>
,但它也适用于引用类型。
public interface ITreeNode<TKey>
{
TKey Id { get; set; }
Maybe<TKey> ParentId { get; set; }
}
这是一个简单的定义:
public class Maybe<T>
{
public readonly static Maybe<T> Nothing = new Maybe<T>();
public T Value { get; private set; }
public bool HasValue { get; private set; }
public Maybe()
{
HasValue = false;
}
public Maybe(T value)
{
Value = value;
HasValue = true;
}
public static implicit operator Maybe<T>(T v)
{
return v.ToMaybe();
}
}
然后你可以这样做:
public class TreeNode<TKey> : ITreeNode<TKey>
{
public TreeNode(TKey id)
: this(id, Maybe<TKey>.Nothing)
{ }
public TreeNode(TKey id, Maybe<TKey> parentId)
{
this.Id = id;
this.ParentId = parentId;
}
public TKey Id { get; set; }
public Maybe<TKey> ParentId { get; set; }
}
然后这个:
ITreeNode<int> a = new TreeNode<int>(5);
ITreeNode<int> b = new TreeNode<int>(5, 1);
ITreeNode<string> c = new TreeNode<string>("q1");
ITreeNode<string> d = new TreeNode<string>("q2", "q1");
然后你可以检查是否有a.ParentId.HasValue
或d.ParentId.HasValue
等的父母。
这是一个有用的扩展类:
public static class MaybeEx
{
public static Maybe<T> ToMaybe<T>(this T value)
{
return new Maybe<T>(value);
}
public static Maybe<U> Select<T, U>(this Maybe<T> m, Func<T, U> k)
{
return m.SelectMany(t => k(t).ToMaybe());
}
public static Maybe<U> SelectMany<T, U>(this Maybe<T> m, Func<T, Maybe<U>> k)
{
if (!m.HasValue)
{
return Maybe<U>.Nothing;
}
return k(m.Value);
}
public static Maybe<V> SelectMany<T, U, V>(this Maybe<T> @this, Func<T, Maybe<U>> k, Func<T, U, V> s)
{
return @this.SelectMany(x => k(x).SelectMany(y => s(x, y).ToMaybe()));
}
}