如何使用我自己的引用类型作为数据视图列的数据类型

How do I use my own reference types as the data type of a dataview column

我有一个包含列的数据表,其中一些列的数据类型是我项目中 class 的类型,因此该列将添加到 table 中:

DataColumn column = _dataTable.Columns.Add("myColumnName", typeof(MyClass));

当我从 DataTable 创建 DataView 并尝试设置 RowFilter 时出现问题:

_dataView.RowFilter = "[myColumnName] = \"xyz\"";

这会引发异常“无法对 MyClass 和 System.String 执行‘=’操作”。

MyClass 实现了 IComparable 以及 Equals(object obj)、ToString() 和所有相等和比较运算符,但这显然是不够的。我什至尝试向 CompareTo(object obj) 添加一个条件分支以接受一个字符串 obj,但无济于事,它甚至从未命中 CompareTo。

大概是 DataView 中的表达式解析器无法计算出如何将 MyClass 与字符串进行比较。

如有任何建议,我将不胜感激。

应 Cee McSharpFace 的要求,这里是我的 class:

的相关部分
public class PartNumber : IXmlSerializable, IComparable<PartNumber>, IArithmetic, IEquatable<PartNumber>, IEquatable<string>, IComparable<string>
{
    public int CompareTo(PartNumber other)
    {
        int result = 0;
        if (other is null)
        {
            result = 1;
        }
        else
        {
            DoActualComparison(other);
        }
        return result;
    }
    public int CompareTo(string other)
    {
        return ToString().CompareTo(other);
    }
    public override int GetHashCode()
    {
        return ToString().GetHashCode();
    }
    public override bool Equals(object obj)
    {
        return !(obj is null) &&
               obj is PartNumber &&
               this == ((PartNumber)obj);
    }
    public static bool operator ==(PartNumber x, PartNumber y)
    {
        return x.CompareTo(y) == 0;
    }
    public static bool operator !=(PartNumber x, PartNumber y)
    {
        return !(x == y);
    }
    public static bool operator >(PartNumber x, PartNumber y)
    {
        return x.CompareTo(y) > 0;
    }
    public static bool operator <(PartNumber x, PartNumber y)
    {
        return x.CompareTo(y) < 0;
    }
    public bool Equals(string other)
    {
        return ToString().Equals(other);
    }
    public bool Equals(PartNumber other)
    {
        return Equals((object)other);
    }
    public static bool operator ==(PartNumber lhs, string rhs)
    {
        return lhs.ToString() == rhs;
    }
    public static bool operator !=(PartNumber lhs, string rhs)
    {
        return lhs.ToString() != rhs;
    }
    public object Add(object x)
    {
        return this;
    }
    public object Subtract(object x)
    {
        return this;
    }
    public object Multiply(object x)
    {
        return this;
    }
    public object Divide(object x)
    {
        return this;
    }
    public override string ToString()
    {
        return MakeObjectIntoString();
    }
}

有一个 PartNumber 类型的列映射到数据表中的内部 StorageType.Object

二元运算求值器不支持此存储类型上的任何运算符:

Reference source,这是它抛出异常的地方。支持的类型列表在 switch 语句中列出了几十行。

解决方法 1:

添加第二列,您只存储 PartNumber.ToString() 结果,预先计算,用于查询。

为了编译您的代码,并出于演示目的,我为部件号添加了一个私有字符串字段,我 return 在其 ToString 覆盖中:

public struct PartNumber : IComparable<PartNumber>, IEquatable<PartNumber>, IEquatable<string>, IComparable<string>
{
    private readonly string actualPartnumber;

    public PartNumber(string samplePartnumber) => this.actualPartnumber = samplePartnumber;

    /* ... */

    public override string ToString() => actualPartnumber;
}

用法:

var dataTable = new DataTable();
var column = dataTable.Columns.Add("myColumnName", typeof(PartNumber));
var columnStr = dataTable.Columns.Add("myColumnNameStr", typeof(String));
var newRow1 = dataTable.NewRow();
newRow1["myColumnName"] = new PartNumber("abc");
newRow1["myColumnNameStr"] = newRow1["myColumnName"].ToString();
dataTable.Rows.Add(newRow1);
var newRow2 = dataTable.NewRow();
newRow2["myColumnName"] = new PartNumber("xyz");
newRow2["myColumnNameStr"] = newRow2["myColumnName"].ToString();
dataTable.Rows.Add(newRow2);

var dataView = new DataView(dataTable)
{
    RowFilter = "[myColumnNameStr] = 'xyz'"
};

Console.WriteLine(dataView.Count);

--> 这 return 是一行,如您所料。

解决方法 2

Convert function 可以处理 StorageType.Object 并且能够正确使用其 ToStringPartNumber 实例转换为字符串。所以这也行得通:

var dataTable = new DataTable();
dataTable.Columns.Add("myColumnName", typeof(PartNumber));
var newRow1 = dataTable.NewRow();
newRow1["myColumnName"] = new PartNumber("abc");
dataTable.Rows.Add(newRow1);
var newRow2 = dataTable.NewRow();
newRow2["myColumnName"] = new PartNumber("xyz");
dataTable.Rows.Add(newRow2);

var dataView = new DataView(dataTable)
{
    RowFilter = "CONVERT([myColumnName], System.String) = 'xyz'"
};

Console.WriteLine(dataView.Count);

--> 我测试了它,它也 return 是正确的(也是唯一的)匹配项。