我可以使用关键字“where”指定“或”通用类型参数约束吗?

时间:2015-07-16 19:05:51

标签: c#

我有一个做加扰比较的功能

    public static int ScrambledEquals<TKey, T>(
      IDictionary<TKey, T> list1, 
      IDictionary<TKey, T> list2)
        where TKey : IComparable
        where T : ICompareAsHtml or IComparable // compilation failure on this line
    {
      // ...
    }

    public static int ScrambledEquals<TKey, T>(
      IDictionary<TKey, T> list1, 
      IDictionary<TKey, T> list2)
        where TKey : IComparable
        where T : ICompareAsHtml {} // This works!

TKey必须是IComparable,但值类型T可以是IComparable或在接口下面实现

    public interface ICompareAsHtml
    {
      // Compare current "this" object with "obj"
      // and persist the difference in html somewhere
      // return number of differences.
      int compareAsHtml(object obj);
    }

如何更新要编译的行传递的位置(不删除它,不使用其中一个接口)?

或者更好的是,您可以阅读下面的代码来了解我的情况。我需要使用下面的函数来比较一个字符串的集合,这是IComparable;或比较一个拥抱类的集合,比如Sales,它实现了ICompareAsHtml而不是IComparable。 (因为太多的属性使得这个类很难实现CompareTo函数 - 不能给出“一个”数字来表示两个实例之间的“方向”和“距离”。)

    public static int ScrambledEquals<TKey, T>(
      IDictionary<TKey, T> list1,
      IDictionary<TKey, T> list2)
    where TKey : IComparable
    // where T : ICompareAsHtml or IComparable
    // commented out above line to make compilation pass
    {
        int nDIff = 0;
        List<TKey> bothKeys = list1.Keys.Union<TKey>(list2.Keys).ToList();
        bothKeys.Sort();
        foreach (TKey key in bothKeys)
        {
            // code omitted - not related to this question 
            {
                    // key exist in both lists.
                    object o1 = list1[key];
                    object o2 = list2[key];
                    if (o1 is IComparable && o2 is IComparable)
                    {
                        IComparable v1 = (IComparable)o1;
                        IComparable v2 = (IComparable)o2;
                        if (0 != v1.CompareTo(v2))
                        {
                            nDIff++;
                            // Save the difference in html
                        }
                    }
                    else if (o1 is ICompareAsHtml && o2 is ICompareAsHtml)
                    {
                        ICompareAsHtml v1 = (ICompareAsHtml)o1;
                        ICompareAsHtml v2 = (ICompareAsHtml)o2;
                        // Save the difference
                        nDIff += v1.compareAsHtml(v2);
                    }
                    else
                    {
                        // If I can use where keyword
                        // I don't need this exception
                        throw new Exception(@"Error: Program error
    - Value Type is neither IComparable nor ICompareAsHtml.");
                    }
                }
            }
        }
        return nDIff;
    }

欢迎所有建议/反馈/意见!

3 个答案:

答案 0 :(得分:3)

这是框架支持的东西。但是,执行此操作的需要意味着缺少IComparableICompareAsHtml应该实现的公共接口,而是可以约束。

这里的坏消息是IComparable是框架的一部分,这意味着你无法改变它来实现那个缺失的界面。好消息是IComparable已经非常简单了......也许它可以 缺少界面。

ICompareAsHtml不是该框架的一部分,我目前无法通过Google搜索任何产品的文档中未提及,这意味着它可能是您可以更改的界面。如果这是真的,只需让ICompareAsHtml实施IComparable并限制为IComparable,就可以满足您的条件

答案 1 :(得分:1)

您无法在约束列表中执行OR,请查看此处的文档: https://msdn.microsoft.com/en-us/library/d5x73970.aspx

也许你能做的就是让你的界面来自IComparable:

public interface ICompareAsHtml : IComparable
{
    int compareAsHtml(object obj);
}

class CompareAsHtml : ICompareAsHtml
{
    public int CompareTo(object obj)
    {
        return compareAsHtml(obj);
    }

    public int compareAsHtml(object obj)
    {
        //do the core comparison here and return
    }
}

答案 2 :(得分:0)

最后,我想出使用两个函数而不是一个

public static int ScrambledEqualsComparable<TKey, T>(
  IDictionary<TKey, T> list1, 
  IDictionary<TKey, T> list2)
    where TKey : IComparable
    where T : IComparable
{
  return ScrambledEquals(list1, list2);
}

public static int ScrambledEqualsCompareAsHtml<TKey, T>(
  IDictionary<TKey, T> list1, 
  IDictionary<TKey, T> list2)
    where TKey : IComparable
    where T : ICompareAsHtml 
{
  return ScrambledEquals(list1, list2);
}

private static int ScrambledEquals<TKey, T>(
  Dictionary<TKey, T> list1, 
  Dictionary<TKey, T> list2)
    where TKey : IComparable
{
  // the same as above code - No need to throw exception as 
  // it has to be one of ICompareAsHtml or IComparable.
}

当然,我可以将ScrambledEqualsCompareAsHtml,ScrambledEqualsComparable重命名为专有名称。但是两个功能可以解决这个问题。当然旧功能改为私有,以避免从外部直接访问。

你觉得这个解决方案怎么样?