从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)
Run Code Online (Sandbox Code Playgroud)//*****NOTICE***** FieldInfo[] fields …
从这个问题简化并摆脱了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).但现在看起来用户定义的运算符的候选列表是空的,最后 …
假设我们有一些像这样的测试接口/类:
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 …
刚刚发现它,Add(T)定义在ICollection<T>,而不是IEnumerable<T>.Enumerable.cs中的扩展方法不包含Add(T),我认为这很奇怪.由于对象是可枚举的,因此它必须"看起来像"一组项目.谁能告诉我为什么?
我在这篇文章和这篇文章中看到了这个属性.当我们需要升级旧系统时,它似乎非常有用.然后我创建一个测试解决方案(其中包含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, …
我认为这种方法有效,但我错了:
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方法中动态调用它.
从规范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个字节)不允许设计的易失性?
它在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?
我刚看到这篇关于时间测量的帖子.我记得(我希望我没有记错)这是一场不公平的比赛,如果以前从未打过这种方法的话.那是:
// 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 ×9
c# ×9
attributes ×2
generics ×2
clr ×1
collections ×1
equals ×1
gethashcode ×1
ienumerable ×1
java ×1
java-8 ×1
performance ×1
volatile ×1
winforms ×1