小编Che*_*hen的帖子

在System.Attribute中错误地实现了GetHashCode和Equals?

Artech的博客看,然后我们在评论中进行了讨论.由于该博客仅以中文撰写,我在此处作简要说明.代码重现:

[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public abstract class BaseAttribute : Attribute
{
    public string Name { get; set; }
}

public class FooAttribute : BaseAttribute { }

[Foo(Name = "A")]
[Foo(Name = "B")]
[Foo(Name = "C")]
public class Bar { }

//Main method
var attributes = typeof(Bar).GetCustomAttributes(true).OfType<FooAttribute>().ToList<FooAttribute>();
var getC = attributes.First(item => item.Name == "C");
attributes.Remove(getC);
attributes.ForEach(a => Console.WriteLine(a.Name));
Run Code Online (Sandbox Code Playgroud)

代码全部获取FooAttribute并删除名称为"C"的代码.显然输出是"A"和"B"?如果一切顺利,你就不会看到这个问题.事实上,理论上你会得到"AC""BC"甚至是"AB"(我的机器上有AC,博客作者有BC).问题源于System.Attribute中GetHashCode/Equals的实现.实现的片段:

  [SecuritySafeCritical]
  public override int GetHashCode()
  {
      Type type = base.GetType();
Run Code Online (Sandbox Code Playgroud)
      //*****NOTICE*****
      FieldInfo[] fields …
Run Code Online (Sandbox Code Playgroud)

.net c# attributes equals gethashcode

14
推荐指数
1
解决办法
983
查看次数

隐式方法组转换问题(第2部分)

这个问题简化并摆脱了LinqPad(没有密集)的可能影响,这样一个简单的控制台应用程序:

public class Program
{
    static void M() { }    
    static void Main(string[] args)
    {
        Action a = new Action(M);
        Delegate b = new Action(M);
        Console.WriteLine(a == b);      //got False here
        Console.Read();
    }        
}
Run Code Online (Sandbox Code Playgroud)

操作员ceq在上述代码的CIL中产生"错误" (有关详细信息,请访问原始问题).所以我的问题是:

(1)为什么==要翻译ceq而不是call Delegate Equals

在这里,我不关心Delegate和Action之间的(un)包装.最后,在评估时a == b,a是类型,Action而b是a Delegate.从规格:

7.3.4二元运算符重载决策

形式为x op y的操作,其中op是可重载的二元运算符,x是类型X的表达式,y是类型Y的表达式,按如下方式处理:

•确定由操作运算符op(x,y)的X和Y提供的候选用户定义运算符集.该集合由X提供的候选运算符和Y提供的候选运算符组合而成,每个运算符使用§7.3.5的规则确定.如果X和Y是相同类型,或者如果X和Y是从公共基类型派生的,则共享候选运算符仅出现在组合集中一次.

•如果候选用户定义的运算符集不为空,则此变为该操作的候选运算符集.否则,预定义的二元运算符op实现(包括它们的提升形式)将成为该操作的候选运算符集.给定运算符的预定义实现在运算符的描述中指定(第7.7节到第7.12节).

•§7.5.3的重载决策规则应用于候选运算符集合,以选择与参数列表(x,y)相关的最佳运算符,并且此运算符成为重载解析过程的结果.如果重载决策未能选择单个最佳运算符,则会发生绑定时错误.

7.3.5候选用户定义的运算符

给定类型T和操作运算符op(A),其中op是可重载运算符,A是参数列表,由T为运算符op(A)提供的候选用户定义运算符集合如下确定:

•确定类型T0.如果T是可空类型,则T0是其基础类型,否则T0等于T.

•对于T0中的所有运算符op声明和此类运算符的所有提升形式,如果关于参数列表A至少有一个运算符适用(第7.5.3.1节),则候选运算符集包含所有此类适用运算符. T0.

•否则,如果T0是对象,则候选运算符集为空.

•否则,T0提供的候选运算符集合是由T0的直接基类提供的候选运算符集合,或者如果T0是类型参数则是T0的有效基类.

从规范中,a和b具有相同的基类Delegate,显然应该在这里应用==定义的运算符规则Delegate(operator ==从本质上调用Delegate.Equals).但现在看起来用户定义的运算符的候选列表是空的,最后 …

.net c# operator-overloading

14
推荐指数
3
解决办法
843
查看次数

为什么接口的泛型方法可以在Java中实现为非泛型?

假设我们有一些像这样的测试接口/类:

abstract class Plant {
    public abstract String getName();
}

interface Eatable { }

class Apple extends Plant implements Eatable {
    @Override
    public String getName() {
        return "Apple";
    }
}

class Rose extends Plant {
    @Override
    public String getName() {
        return "Rose";
    }
}

interface Animal {
    <T extends Plant & Eatable> void eat(T plant);
}
Run Code Online (Sandbox Code Playgroud)

您可以看到Animal.eat具有约束的通用方法.现在我的Human班级是这样的:

class Human implements Animal {
    @Override
    public void eat(Plant plant) {
    }
}
Run Code Online (Sandbox Code Playgroud)

编译好.你可以看到Human.eat比限制较少Animal.eat,因为Eatable …

java generics java-8 generic-constraints

14
推荐指数
1
解决办法
155
查看次数

c#中的非自动阻塞MessageBoxes

任何人都知道.NET中的messageBox不会阻止创建它的线程,直到它关闭?

.net c# winforms

13
推荐指数
4
解决办法
1万
查看次数

为什么IEnumerable <T>没有实现Add(T)?

刚刚发现它,Add(T)定义在ICollection<T>,而不是IEnumerable<T>.Enumerable.cs中的扩展方法不包含Add(T),我认为这很奇怪.由于对象是可枚举的,因此它必须"看起来像"一组项目.谁能告诉我为什么?

.net c# generics collections ienumerable

12
推荐指数
3
解决办法
2989
查看次数

使用TypeForwardedToAttribute的正确方法是什么?

我在这篇文章这篇文章中看到了这个属性.当我们需要升级旧系统时,它似乎非常有用.然后我创建一个测试解决方案(其中包含3个项目)以使用此属性.首先是一个名为"Animal"的类库项目.

namespace Animal
{
   public class Dog
   {
      public static string Name = "old version";
   }
}
Run Code Online (Sandbox Code Playgroud)

然后我创建一个控制台应用程序项目,添加"Animal"作为参考,并在Main我有的方法中:

Console.WriteLine(Animal.Dog.Name);
Run Code Online (Sandbox Code Playgroud)

现在它打印"旧版本".大!现在我开始"升级"现有项目.我删除了Dog"Animal" 中的类,添加了另一个名为"AdvancedAnimal"的类库项目,其中包含:

namespace Animal
{
   public class Dog
   {
      public static string Name = "new version";
   }
}
Run Code Online (Sandbox Code Playgroud)

添加"AdvancedAnimal"作为"Animal"中的引用.还AssemblyInfo.cs"动物"的,通过添加改性:

[assembly: TypeForwardedTo(typeof(Animal.Dog))]
Run Code Online (Sandbox Code Playgroud)

从这个属性的用法,从现在开始,所有内容都Animal.Dog被转发到Dog"AdvancedAnimal"中的类(实际上Dog动物中没有类了).我重新编译整个解决方案,并希望控制台应用程序打印"新版本".但它给了我一个编译错误:

The type name 'Dog' could not be found in the namespace 'Animal'. This type has been forwarded to assembly 'AdvancedAnimal, Version=1.0.0.0, Culture=neutral, …

.net c# attributes

12
推荐指数
1
解决办法
4690
查看次数

运算符'=='无法应用于类型T?

我认为这种方法有效,但我错了:

static void Equals<T>(T x, T y)
{
    return x == y;    //operator == can't be applied to type T
}
Run Code Online (Sandbox Code Playgroud)

在阅读了规范(v3.0中的第7.2.4节和v4.0中的第7.3.4节)之后:

7.2.4二元运算符重载决策

形式为x op y的操作,其中op是可重载的二元运算符,x是类型X的表达式,y是类型Y的表达式,按如下方式处理:

  • 由X和Y为操作运算符op(x,y)提供的候选用户定义运算符集合被确定.该集合由X提供的候选运算符和Y提供的候选运算符组合而成,每个运算符使用§7.2.5的规则确定.如果X和Y是相同类型,或者如果X和Y是从公共基类型派生的,则共享候选运算符仅出现在组合集中一次.

  • 如果候选用户定义的运算符集合不为空,则这将成为该操作的候选运算符集.否则,预定义的二元运算符op实现(包括它们的提升形式)将成为该操作的候选运算符集.给定运算符的预定义实现在运算符的描述中指定(第7.7节到第7.11节).

  • §7.4.3的重载决策规则应用于候选运算符集合,以根据参数列表(x,y)选择最佳运算符,并且此运算符成为重载解析过程的结果.如果重载解析无法选择单个最佳运算符,则会发生编译时错误.

在第2步中,我认为应该应用此预定义实现:

bool operator ==(object x, object y);
bool operator !=(object x, object y);
Run Code Online (Sandbox Code Playgroud)

因为C#中的所有内容都来自Object.如何在步骤3中发生编译时错误?在这种情况下,我不认为"重载决议无法选择".

编辑当我实现这样的事情时,我想到了这个问题:

class EnumComparer<TEnum> : IEqualityComparer<TEnum>
{
    public bool Equals(TEnum x, TEnum y)
    {
        return x == y;
    }
    public int GetHashCode(TEnum obj)
    {
        return (int)obj;
    }
}
Run Code Online (Sandbox Code Playgroud)

我担心我需要构建一个表达式并在Equals方法中动态调用它.

.net c# operator-overloading language-specifications

12
推荐指数
2
解决办法
2564
查看次数

C#中的易失性字段

从规范10.5.3挥发性字段:


volatile字段的类型必须是以下之一:

  • 引用类型.

  • 类型byte,sbyte,short,ushort,int,uint,char,float,bool,System.IntPtr或System.UIntPtr.

  • 具有枚举基类型byte,sbyte,short,ushort,int或uint的枚举类型.


首先,我想确认我的理解是正确的:我猜上面的类型可以是volatile,因为它们在内存中存储为4字节单元(因为它的地址对于引用类型),这保证了读/写操作是原子的.double/long/etc类型不能是volatile,因为它们不是原子读/写,因为它们在内存中超过4个字节.我的理解是否正确?

第二,如果第一个猜测是正确的,为什么用户定义的结构只有一个int字段(或类似的东西,4个字节就可以)不能是易失性的?理论上它是原子的吗?或者仅仅是因为所有用户定义的结构(可能超过4个字节)不允许设计的易失性?

.net c# clr language-features volatile

11
推荐指数
1
解决办法
3422
查看次数

任何人都可以给我看一个MethodImplOptions.ForwardRef的例子

它在MSDN上看起来很酷:

指定声明方法,但其实现在别处提供.

所以我在控制台应用程序中尝试了它:

public class Program
{
    [MethodImplAttribute(MethodImplOptions.ForwardRef)]
    public static extern void Invoke();

    static void Main(string[] args)
    {
        Invoke();
        Console.Read();
    }
}
Run Code Online (Sandbox Code Playgroud)

那我现在该怎么办?我在哪里可以提供实施Program.Invoke

.net c# methodimplattribute external-methods

11
推荐指数
2
解决办法
1289
查看次数

在C#中调用方法时的预热

我刚看到这篇关于时间测量的帖子.我记得(我希望我没有记错)这是一场不公平的比赛,如果以前从未打过这种方法的话.那是:

// At the beginning of the application
MyClass instance = new MyClass();
instance.MyMethod();
instance.MyMethod();  // Faster than the first call, because now it's warmed up.
Run Code Online (Sandbox Code Playgroud)

我们真的在C#中有这样的热身理论吗?如果是,为什么(热身时CLR会做什么)?如果这个方法是扩展方法(静态方法),那么一切都是一样的吗?

.net c# performance extension-methods

10
推荐指数
2
解决办法
2585
查看次数