C# 对我的比较者不必要的施法?

C# 对我的比较者不必要的施法?,c#,interface,casting,C#,Interface,Casting,我了解如何将IComparer接口与提供自定义排序方法的帮助器类一起使用。例如,这里有一个典型示例,与我在web上看到的所有示例非常相似,包括Microsoft的联机帮助页: // This helper class is used to sort an array of people by name, // where 'Person' is a class type. public class PeopleNameComparer : IComparer { // Test the n

我了解如何将IComparer接口与提供自定义排序方法的帮助器类一起使用。例如,这里有一个典型示例,与我在web上看到的所有示例非常相似,包括Microsoft的联机帮助页:

// This helper class is used to sort an array of people by name, 
// where 'Person' is a class type.
public class PeopleNameComparer : IComparer
{
  // Test the name of each object.
  int IComparer.Compare(object o1, object o2)
  {
     Person p1 = o1 as Person;
     Person p2 = o2 as Person;
     if (p1 != null && p2 != null)
        return string.Compare(p1.Name, p2.Name);
     else
        throw new ArgumentException("Parameter is not a Person!");
  }
}
我还了解到,如果我们有一个Person(myPeople)类型的数组,那么我们可以使用以下方法对该数组进行排序:

Array.Sort(myPeople, new PeopleNameComparer());
在本例中,我们将创建一个新的PeopleNameComparer对象,该对象的类型为IComparer,并将其作为第二个参数传递到Array.Sort()方法中

现在,为了使事情更整洁,我们可以实现一个属性,为对象用户提供一种更友好的方式来调用自定义排序:

public static IComparer SortByName
{ get { return (IComparer)new PeopleNameComparer(); } }
对于此类属性,我不理解的是,为什么所有示例都使用(IComparer)强制转换将新创建的帮助器类(本例中为PeopleNameComparer)强制转换为IComparer对象,而该对象已经是IComparer类型?我在没有演员阵容的情况下尝试过,代码似乎很好:

// This property seems to work fine without the cast?
public static IComparer SortByName
{ get { return new PeopleNameComparer(); } }
如果“new”关键字返回一个普通的System.Object类型,那么我可以理解,该类型必须被转换为相应的IComparer,但我看不出这里需要转换。 但我遵循了微软的例子,我的例子与我的专业C#书中的一个例子类似

这里有必要进行强制转换的原因吗?

强制转换是多余的

也许这在代码从其他东西重构之前是必要的

通常,在设计发生变化的长系统生命周期中,您会看到代码中留下了大量的绒毛

随着时间的推移,当语言特性(即C#automatic属性)发生变化时,您可能还会看到其他冗余结构


我认为冗余代码会降低可读性,像Resharper这样的工具会警告您并帮助您删除这些代码。

如果您的问题仅仅是为什么示例会将PeopleNameComparer转换为IComparer,那么您完全可以理解这一点。我想,为了清晰起见,应该向初学者演示结果和接口之间存在隐含的关系。

我不知道“所有”示例,但实际上,这两种代码应该是相同的。也许他们只是认为显式转换更具可读性。

使用显式转换更显式。请原谅这句老生常谈。。但就是这样。它有助于提高代码的可读性

在某些情况下,如果存在多个可能的选项,但返回类型似乎不会出现这种情况,则显式强制转换可以帮助运行时消除强制转换的歧义。只有在表达上。以下是一个常见示例,其中需要在表达式中进行显式强制转换:

public class StringEnumerable : IEnumerable, IEnumerable<String>
{
    IEnumerator<String> IEnumerable<String>.GetEnumerator()
    {
        yield return "TEST";
    }

    public IEnumerator GetEnumerator()
    {
        // without the explicit cast of `this` to the generic interface the 
        // method would call itself infinitely until a StackOverflowException occurs
        return ((IEnumerable<String>)this).GetEnumerator();
    }
}
公共类StringEnumerable:IEnumerable,IEnumerable
{
IEnumerator IEnumerable.GetEnumerator()
{
收益率回归“测试”;
}
公共IEnumerator GetEnumerator()
{
//如果没有将'this'显式强制转换到泛型接口
//方法将无限地调用自身,直到发生StackOverflowException
返回((IEnumerable)this.GetEnumerator();
}
}

如果从非泛型接口实现中删除显式强制转换,将导致无限循环。

这就是问题所在,而“也许”并不是答案。评论?史蒂文·杰里斯OP主要问为什么这些例子包括多余的演员阵容。原因可能有很多。我认为这实际上比“明确性”的明确演员阵容更有可能。通常情况下,你会发现在设计周期已经改变的长系统生命周期中,代码中留下了大量的绒毛。你可能会有一点,考虑更新(扩展)你的答案,这样我就可以移除向下的投票。在参考书中的例子中,代码中确实没有任何绒毛,确实是微软公司自己的例子。因为微软把这个看似多余的角色放进去了,我想知道是否有一个好的理由?@Yarc很难知道。你会认为这些例子是干净的。我知道我通常会把多余的东西都拿出来。代码越少,出错的地方就越少。你的问题标题和实际问题之间有什么联系?好的,谢谢你更新这个问题。现在是我等待的非“可能”答案;P然而,我开始想知道,你能举一个例子,其中一个演员可能是模棱两可的?当然,它是否可读是一个意见问题。我发现属性的返回类型足够可读。@StevenJeuris-是的,我认为返回语句需要显式类型转换。只有在表达中,歧义才会随之而来。我将修改我的答案以反映这一点。谢谢你的回答,尽管你给出的最后一个例子与我最初的问题不同,但有趣的是,这是可能的,尽管属性返回类型应该足够清楚。我同意。由于返回值没有被存储,而且getter非常简单,我个人认为它没有增加任何清晰度。