简体   繁体   English

C#中的匿名内部类?

[英]Anonymous inner classes in C#?

Is there something like anonymous inner classes (used in Java) in C#? C#中是否有类似匿名内部类(在Java中使用)的东西?

I explain what I would use it for by example: I'm declaring and initializing field of type IDictionary<Person, Account> and I need to write custom IEqualityComparer<Person> . 我举例说明了它的用途:我声明并初始化了IDictionary<Person, Account>类型的字段,并且需要编写自定义IEqualityComparer<Person> That is because I want two Persons to be treated as equal by the IDictionary when they have equal names and IDs (not only IDs as it is by default). 这是因为我希望两个人在名称和ID相同(不仅是默认情况下的ID)时被IDictionary视为相等。 I will not need this IEqualityComparer<Person> anywhere else in the code. 我在代码中的其他任何地方都不需要IEqualityComparer<Person>

So I do I have to declare new class that implements IEqualityComparer<Person> to do this ? 所以我必须声明实现IEqualityComparer<Person>新类来做到这一点吗? In Java I would use anonymous class, something like this(this is mixed C#-Java syntax, just to show what functionality I'm looking for): 在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();
        }
    });

Is something like this in C# ? 在C#中是这样的吗? I'm too lazy to write new class every time I need something like this. 每当我需要这样的东西时,我都懒得写新课。

Note: This is syntax question. 注意:这是语法问题。 I know how to write it, but I want to know if it's possible to make the code shorter. 我知道如何编写,但是我想知道是否可以使代码更短。

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

EDIT: How do you yourself code similar cases ? 编辑:您自己如何编码类似的情况? Do you create new class to implement the interface or what do you do ? 您是创建新类来实现接口还是做什么? Maybe you have some trick that I might like. 也许您有一些我可能喜欢的把戏。

EDIT What about future support for anonymous classes like those in Java ? 编辑将来如何支持Java中的匿名类? Have you heard something about it ? 你听说过什么吗?

EDIT: Well I see I'll have to provide my actual code - not just an example. 编辑:嗯,我看到我必须提供我的实际代码-而不仅仅是一个例子。 That's because I don't know if it's going to work with Jon's Skeet's solution. 那是因为我不知道它是否可以与Jon's Skeet的解决方案一起使用。

The actual reason why I don't just implement Equals(object) and GetHashCode in the class itself is, that it's class(entity) generated by ER framework from model diagram. 我不只是在类本身中实现Equals(object)GetHashCode的实际原因是,它是ER框架从模型图中生成的类(实体)。 If I implemented it in class itself my code would be deleted from the class(entity) every time I update the model from database (using "update from database" feature). 如果我在类本身中实现它,则每次我从数据库更新模型时(使用“从数据库更新”功能),我的代码都将从类(实体)中删除。 The class is actually called Font not Person . 该类实际上称为Font而不是Person It has this properities: 它具有以下特性:

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

Where Color is another class (entity) generated from database. 其中Color是从数据库生成的另一个类(实体)。

This are properties of Color: 这是颜色的属性:

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

So I cannot modify Font, neither Color (if I don't want to rewrite those changes over and over again every time I change database) What I want is to have this Dictionary : 因此,我既不能修改字体,也不能修改颜色(如果我不想每次更改数据库时都一遍又一遍地重写那些更改),我想要的就是拥有这个Dictionary

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

And the comparer SomeEqualityComparer should ensure that two Fonts would be considered equal if and only if all the properties listed above(except Id ) are equal. 并且比较器SomeEqualityComparer应该确保并且仅当以上列出的所有属性( Id除外)相等时,两个SomeEqualityComparer才视为相等。 In the case of last property Foreground two Color s are considered equal when all their properties(except Id ) are equal. 在最后一个属性Foreground的情况下,两个Color的所有属性( Id除外)均相等时,它们被视为相等。

Now if I use solution that Jon Skeet has kindly recommended me, I'm not sure if that can be ensured. 现在,如果我使用Jon Skeet推荐给我的解决方案,我不确定是否可以保证。 If I used something like: 如果我使用类似:

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});

I'd guess that anonymous types call Equals(object) on all properties when their Equals(object) is called. 我猜想,匿名类型调用Equals(object)的所有属性时,他们Equals(object)被调用。 However as I cannot override Color 's Equals(object) it would not compare Color s as I want (using all properties except Id ) so also the equality of Font s would be tested incorrectly. 但是,由于我无法覆盖ColorEquals(object) ,因此无法按我的意愿比较Color s(使用除Id之外的所有属性),因此Font的相等性也将被错误地测试。 Am I right ? 我对吗 ?

I have a ProjectionEqualityComparer class you could use in MiscUtil . 我有一个可以在MiscUtil中使用的ProjectionEqualityComparer类。 You'd use code like this: 您将使用如下代码:

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

Thhat uses the fact that anonymous types have appropriate equality notions built in - when the ProjectionEqualityComparer is asked to compare two people for equality, it will project each to the anonymous type, and compare those instances. Thhat使用了以下事实:匿名类型具有内置的适当的相等概念-当要求ProjectionEqualityComparer比较两个人的相等性时,它将把每个人ProjectionEqualityComparer到匿名类型,并比较那些实例。 Likewise when it's asked for a hashcode, it will perform the projection and ask that for its hash code. 同样,当要求提供哈希码时,它将执行投影并要求其提供哈希码。

EDIT: To tackle your colour problem, you're right: if Color doesn't override Equals/GetHashCode in the way that you want, you can't use it directly. 编辑:要解决您的颜色问题,您是对的:如果Color并未以您想要的方式覆盖Equals / GetHashCode,您将无法直接使用它。 However, you can do this instead: 但是,您可以改为:

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});

If you're able to modify the Color type in terms of properties, it would be simpler if you could give it an ARGB property generated from the others, so you could write: 如果您可以根据属性修改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 });

That's pretty ugly, but it should work... 这很丑陋,但应该可以...

No there isn't. 不,没有。 There are anonymous types eg 有匿名类型,例如

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

but they are very limited, and only contain read only properties and no methods. 但是它们非常有限,并且仅包含只读属性,而没有方法。

The literal answer is that no, C# doesn't have anonymous inner classes, because Java added those to get around its lack of first-class functions, which C# does have. 字面上的答案是不,C#没有匿名内部类,因为Java添加了那些内部类来解决C#确实缺乏一流的功能。 More specifically, to solve your problem, you can just implement IEquatable<Person> on your Person class, and then IDictionary will use that automatically. 更具体地说,要解决您的问题,只需在Person类上实现IEquatable<Person> ,然后IDictionary将自动使用它。 That's the most common solution to this problem and works as long as your OK with the process for comparing Persons being baked into that class. 这是解决该问题的最常见方法,并且只要您可以比较比较被烘焙到该类中的人员的过程,就可以使用该方法。

If you want the comparison/equality logic to not be tied directly to Person , most collections in .NET allow you to pass in a Comparison<T> object (which is a delegate, not an interface), letting you do nice in-place sorting logic. 如果您不希望将比较/相等逻辑直接绑定到Person ,.NET中的大多数集合都允许您传入一个Comparison<T>对象(它是一个委托,而不是一个接口),从而就地进行处理排序逻辑。 For example, to sort a list of people by name, you could do: 例如,要按姓名对人员列表进行排序,可以执行以下操作:

List<Person> people = ...
people.Sort((x, y) => x.Name.CompareTo(x.y));

Unfortunately, Dictionary doesn't have something similar to an equality function. 不幸的是, Dictionary没有与相等函数相似的东西。 In .NET 4.0, the stock answer seems to be to override EqualityComparer<T> : 在.NET 4.0中,最佳答案似乎是重写EqualityComparer<T>

public class PersonComparer : EqualityComparer<Person>
{
    public override bool Equals(Person a, Person b)
    {
        return a.Id == b.Id && a.Name == b.Name;
    }
}

Having to define a new class each time you need to compare, though, is a chore. 但是,每次需要比较时都必须定义一个新类,这很麻烦。 What I'd do is make a generic one that takes a function: 我要做的是制作一个具有功能的通用类:

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;
}

Add a little helper class: 添加一个小助手类:

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

And then your solution becomes: 然后您的解决方案变为:

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

Even shorter than it would be in Java. 甚至比Java中的还要短。

In your last edit you mention that the reason that you don't implement Equals and GetHashCode is because the code for your classes is auto-generated and you don't want to have to re-implement that code each time you regenerate the code. 在上次编辑中,您提到未实现Equals和GetHashCode的原因是因为类的代码是自动生成的,并且您不需要在每次重新生成代码时都重新实现该代码。

That's one of the scenarios for which partial classes were introduced in C# 是在C#中引入部分类的场景之一

A lot of code generation tools will generate classes with the partial keyword to allow you to take advantage of that feature. 许多代码生成工具会生成带有partial关键字的类,以使您能够利用该功能。 Check if the classes that are being generated for your code are partial. 检查为您的代码生成的类是否是局部的。

In a separate file (or files) that won't be overwritten when you regenerate the code, within the same assembly, you could have something like the following: 在同一程序集中的一个单独的文件(一个或多个文件)中,当您重新生成代码时,这些文件不会被覆盖,您可能会遇到类似以下内容的情况:

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()
    {
        // ...
    }
}

The closest you're going to get is anonymous types like you'd see in a LINQ expression. 您将获得的最接近的是匿名类型,就像您在LINQ表达式中看到的那样。 A short example from the link: 链接中的一个简短示例:

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

Definitely not what you're looking for. 绝对不是您要找的东西。 I haven't heard of future support for anonymous classes in C# either. 我也没有听说过将来对C#中的匿名类的支持。

不,自最初编写该问题时(C#3.0)起,还没有。

您可以在一个位置(一个类)中定义接口的实现,在您喜欢的IOC框架中将接口映射到所需的实现类,而根本不必考虑实例化一次使用一次的匿名实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM