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将被错误地测试。我是对的吗?
答案 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>