C#中的匿名内部类?

时间:2010-08-22 20:30:49

标签: c# java syntax

C#中是否存在类似匿名内部类(在Java中使用)的内容?

我通过示例解释我将使用它:我正在声明并初始化类型IDictionary<Person, Account>的字段,我需要编写自定义IEqualityComparer<Person>。这是因为当IDictionary具有相同的名称和ID时,我希望两个人被IDictionary视为相等(默认情况下不仅是ID)。代码中的任何其他位置我都不需要IEqualityComparer<Person>

所以我必须声明实现IEqualityComparer<Person>的新类来执行此操作?在Java中我会使用匿名类,类似这样(这是混合C#-Java语法,只是为了显示我正在寻找的功能):

IDictionry<Person, Account> myDict = new Dictionary<Person, Account>(
    new IEqualityComparer<Person>(){
        public bool Equals(Person a, Person b){
            return a.Id == b.Id && a.Name == b.Name;
        }

        public int GetHashCode(Person p){
            return p.Id.GetHashCode() * p.Name.GetHashCode();
        }
    });

在C#中是这样的吗?每次我需要这样的东西时,我都懒得写新课。

注意:这是语法问题。我知道如何编写它,但我想知道是否可以缩短代码。

-------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- ------

编辑:您自己如何编写类似案例的代码?您是否创建了新类来实现界面,或者您做了什么?也许你有一些我可能喜欢的技巧。

编辑对Java等匿名类的未来支持怎么样?你听说过吗?

编辑:我看到我必须提供我的实际代码 - 而不仅仅是一个例子。那是因为我不知道它是否适用于Jon的Skeet解决方案。

我不仅在类本身中实现Equals(object)GetHashCode的实际原因是,它是由模型图中的E-R框架生成的类(实体)。如果我在类本身实现它,每次从数据库更新模型时都会从类(实体)中删除我的代码(使用“从数据库更新”功能)。该类实际上称为Font而不是Person。它具有以下特点:

Id: int
FamilyName:string
Size:int
Bold:bool
Italic:bool
Underlined:bool
Striked:bool
Foreground:Color

其中Color是从数据库生成的另一个类(实体)。

这是Color的属性:

Id:int
Alpha:byte
Red:byte
Green:byte
Blue:byte

所以我不能修改Font,也不能修改Color(如果我不想每次更改数据库时反复重写这些更改)我想要的是Dictionary

private IDictionary<Font, Something> cache = new Dictionary<Font, Something>(new SomeEqualityComparer());

当且仅当上面列出的所有属性(SomeEqualityComparer除外)相等时,比较器Id应确保两个字体被视为相等。在最后一个属性Foreground的情况下,当所有属性(Color除外)相等时,两个Id被认为是相等的。

现在,如果我使用Jon Skeet友好推荐的解决方案,我不确定是否可以确保这一点。 如果我使用了类似的东西:

private IDictionary<Font, Something> cache = new Dictionary<Font, Something>(ProjectionEqualityComparer<Font>.Create
(f => new { f.FontName, f.Size, f.Bold, f.Italic, f.Underlined, f.Striked, f.Foreground});

我猜测匿名类型会在调用Equals(object)时调用所有属性上的Equals(object)。但是,由于我无法覆盖Color的{​​{1}},因此我不会按照我的意愿(使用除Equals(object)之外的所有属性)来比较Color,因此Id也是相等的s将被错误地测试。我是对的吗?

7 个答案:

答案 0 :(得分:13)

我可以在MiscUtil中使用ProjectionEqualityComparer课程。你可以使用这样的代码:

IEqualityComparer<Person> comparer = ProjectionEqualityComparer<Person>.Create
    (p => new { p.Name, p.Id });

使用匿名类型具有内置适当的相等概念的事实 - 当要求ProjectionEqualityComparer比较两个人的相等性时,它会将每个人投射到匿名类型,并比较这些实例。同样,当它被要求提供哈希码时,它将执行投影并询问其哈希码。

编辑:要解决您的颜色问题,您说得对:如果Color没有以您想要的方式覆盖Equals / GetHashCode,则无法直接使用它。但是,您可以执行此操作:

private IDictionary<Font, Something> cache = new Dictionary<Font, Something>
   (ProjectionEqualityComparer<Font>.Create(f => new { 
        f.FontName, f.Size, f.Bold, f.Italic, f.Underlined, f.Striked, 
        f.Foreground.Alpha, f.Foreground.Red, f.Foreground.Green,
        f.Foreground.Blue});

如果您能够在属性方面修改Color类型,那么如果您可以为其他人生成ARGB属性会更简单,那么您可以写:

private IDictionary<Font, Something> cache = new Dictionary<Font, Something>
   (ProjectionEqualityComparer<Font>.Create(f => new { 
        f.FontName, f.Size, f.Bold, f.Italic, f.Underlined, f.Striked, 
        f.Foreground.ARGB });

这很难看,但应该有用......

答案 1 :(得分:2)

不,没有。有匿名类型,例如

var MyType = new { id=1, name="john", dept = "sales" };

但它们非常有限,只包含只读属性而没有方法。

答案 2 :(得分:2)

字面上的答案是,不,C#没有匿名内部类,因为Java添加了那些来解决它缺乏C#所具有的一流函数。更具体地说,要解决您的问题,您只需在IEquatable<Person>课程上实施Person,然后IDictionary将自动使用该Person课程。这是解决这个问题的最常见的解决方案,并且只要您将正在进行比较的人员进行比较就可以了。

如果您希望比较/相等逻辑不直接绑定到Comparison<T>,.NET中的大多数集合允许您传入List<Person> people = ... people.Sort((x, y) => x.Name.CompareTo(x.y)); 对象(它是委托,而不是接口) ,让你做好的就地排序逻辑。例如,要按名称对人员列表进行排序,您可以执行以下操作:

Dictionary

不幸的是,EqualityComparer<T>没有类似于相等函数的东西。在.NET 4.0中,股票回答似乎是覆盖public class PersonComparer : EqualityComparer<Person> { public override bool Equals(Person a, Person b) { return a.Id == b.Id && a.Name == b.Name; } }

public class Equality<T> : EqualityComparer<T>
{
    public Equality(Func<T, T, bool> comparer)
    {
        this.comparer = comparer;
    }

    public override bool Equals(T a, T b)
    {
        return comparer(a, b);
    }

    private Func<T, T, bool> comparer;
}

每次需要比较时,必须定义一个新类,这是一件苦差事。我要做的是制作一个带有函数的通用的:

public static class Equality
{
    public static Equality<T> Create<T>(Func<T, T, bool> comparer)
    {
        return new Equality<T>(comparer);
    }
}

添加一个小助手类:

IDictionary<Person, Account> myDict = new Dictionary<Person, Account>(
    Equality.Create((a, b) => a.Id == b.Id && a.Name == b.Name);

然后你的解决方案就变成了:

{{1}}

甚至比在Java中更短。

答案 3 :(得分:2)

在上一次编辑中,您提到未实现Equals和GetHashCode的原因是因为您的类的代码是自动生成的,并且您不希望每次重新生成时都必须重新实现该代码代码。

这是partial classes were introduced in C#

的方案之一

许多代码生成工具都会使用partial关键字生成类,以便您可以利用该功能。检查为代码生成的类是否是部分的。

在重新生成代码时不会覆盖的单独文件(或多个文件)中,在同一个程序集中,您可以使用以下内容:

partial class Font
{
    public override bool Equals(object obj)
    {
        // ...
    }

    public override int GetHashCode()
    {
        // ...
    }
}

partial class Color
{
    public override bool Equals(object obj)
    {
        // ...
    }

    public override int GetHashCode()
    {
        // ...
    }
}

答案 4 :(得分:1)

你最接近的是anonymous types就像你在LINQ表达式中看到的一样。链接的一个简短示例:

var v = new { Amount = 108, Message = "Hello" };

绝对不是你想要的。我还没有听说过将来对C#中的匿名类的支持。

答案 5 :(得分:0)

不,截至这个问题最初编写时(C#3.0),没有。

答案 6 :(得分:0)

您可以在一个地方定义接口的实现,1个类,将接口映射到您喜欢的IOC框架中的所需实现类,而不必考虑实例化一次性使用匿名实现。< / p>