我正在编写自定义安全属性并得到奇怪的编译器行为...当我在同一文件中使用该属性时,默认参数值工作正常:
using System.Security.Permissions;
[System.Serializable]
sealed class FooAttribute : CodeAccessSecurityAttribute {
public FooAttribute(SecurityAction action = SecurityAction.Demand) : base(action) { }
public override System.Security.IPermission CreatePermission() { return null; }
}
[Foo] class Program {
static void Main(string[] args) { }
}
Run Code Online (Sandbox Code Playgroud)
但是当我将上面的代码分成两个文件时 - 文件1:
using System.Security.Permissions;
[System.Serializable]
sealed class FooAttribute : CodeAccessSecurityAttribute {
public FooAttribute(SecurityAction action = SecurityAction.Demand) : base(action) { }
public override System.Security.IPermission CreatePermission() { return null; }
}
Run Code Online (Sandbox Code Playgroud)
和文件2:
[Foo] class Program {
static void Main(string[] args) { } …Run Code Online (Sandbox Code Playgroud) using System;
using System.Linq.Expressions;
class Program
{
static void Main()
{
Expression<Func<float, uint>> expr = x => (uint) x;
Func<float,uint> converter1 = expr.Compile();
Func<float,uint> converter2 = x => (uint) x;
var aa = converter1(float.MaxValue); // == 2147483648
var bb = converter2(float.MaxValue); // == 0
}
}
Run Code Online (Sandbox Code Playgroud)
编译Expression.Convert此转换时可以建立相同的不同行为:
Single -> UInt32
Single -> UInt64
Double -> UInt32
Double -> UInt64
看起来很奇怪,不是吗?
<===添加了一些我的研究===>
我看了DynamicMethod使用DynamicMethod Visualizer编译的MSIL代码和一些反射hack来DynamicMethod从编译中获取Expression<TDelegate>:
Expression<Func<float, uint>> expr = x => (uint) …Run Code Online (Sandbox Code Playgroud) 在搜索用户定义的运算符时,表达式类应该更准确吗?
sealed class Foo
{
// just the private static method!
private static int op_Implicit() { return 1; }
public static implicit operator int(Foo foo) { return 2; }
}
public class Program
{
private static void Main()
{
var param = Expression.Parameter(typeof(Foo), "x");
// IndexOutOfRangeException was unhandled!
var lambda = Expression.Lambda<Func<Foo, int>>(
Expression.Convert(param, typeof (int)), param);
}
}
Run Code Online (Sandbox Code Playgroud)
此外,可以使用多个参数定义static op_Explicit或op_Implicitmethod,Expression类将此方法作为用户定义的运算符接受!
ps ExpressionTrees正在寻找带有BindingFlags.NonPublicflag的运算符,它允许搜索用户类型中的运算符,而不是System.Core.dll直接可见,但它也允许Expressions API查找"看起来像"用户定义的运算符的私有方法.但是C#规则不允许您定义和使用非公共运算符!我认为Expressions API的行为应该是相同的......
从一些特殊类型的CLI mscorlib程序库(ArgIterator,TypedReference和RuntimeArgumentHandle类型)不能被用作一般类型参数构造通用类型/方法:
void Foo<T>() { }
void Bar() { Foo<ArgIterator>(); }
Run Code Online (Sandbox Code Playgroud)
提供编译器错误:
error CS0306: The type 'System.ArgIterator' may not be used as a type argument
Run Code Online (Sandbox Code Playgroud)
但是在C#规范中根本没有记录.
这些类型是CLI规范的一部分还是CLR实现提供的这种类型,上述行为不应该在C#规范中记录?
在我发现之前的很长一段时间,新的dynamic关键字与C#的foreach声明不兼容:
using System;
sealed class Foo {
public struct FooEnumerator {
int value;
public bool MoveNext() { return true; }
public int Current { get { return value++; } }
}
public FooEnumerator GetEnumerator() {
return new FooEnumerator();
}
static void Main() {
foreach (int x in new Foo()) {
Console.WriteLine(x);
if (x >= 100) break;
}
foreach (int x in (dynamic)new Foo()) { // :)
Console.WriteLine(x);
if (x >= 100) break;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我期望迭代 …
我想知道为什么基类库中的.NET异常类默认有一些可变成员
Source,HelpLink和值Data,但不能改变其他任何像Message?StackTrace使它变得可变?将堆栈跟踪信息附加到现有跟踪是更好的设计(但仍然可变)?我只是在设计选择上很有意思......
class C<T> where T : struct {
bool M1(object o) => o is T;
bool M2(object o) => o is T?;
}
Run Code Online (Sandbox Code Playgroud)
传递null引用或盒装T值时,上述两种方法似乎表现相同.但是,生成的MSIL代码有点不同:
.method private hidebysig instance bool M1(object o) cil managed {
.maxstack 8
IL_0000: ldarg.1
IL_0001: isinst !T
IL_0006: ldnull
IL_0007: cgt.un
IL_0009: ret
}
Run Code Online (Sandbox Code Playgroud)
VS
.method private hidebysig instance bool M2(object o) cil managed {
.maxstack 8
IL_0000: ldarg.1
IL_0001: isinst valuetype [mscorlib]System.Nullable`1<!T>
IL_0006: ldnull
IL_0007: cgt.un
IL_0009: ret
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,o is …
看起来ExpressionTrees编译器应该在许多行为中接近C#规范,但与C#不同,不支持从decimal任何行为转换enum-type:
using System;
using System.Linq.Expressions;
class Program
{
static void Main()
{
Func<decimal, ConsoleColor> converter1 = x => (ConsoleColor) x;
ConsoleColor c1 = converter1(7m); // fine
Expression<Func<decimal, ConsoleColor>> expr = x => (ConsoleColor) x;
// System.InvalidOperationException was unhandled
// No coercion operator is defined between types
// 'System.Decimal' and 'System.ConsoleColor'.
Func<decimal, ConsoleColor> converter2 = expr.Compile();
ConsoleColor c2 = converter2(7m);
}
}
Run Code Online (Sandbox Code Playgroud)
其他很少使用的C#显式转换,如double -> enum-type存在,并按照C#规范中的说明工作,但不是decimal -> enum-type.这是一个错误吗?
我正在尝试使用显式类型参数和约束来定义运算符:
let inline (===)<'a, 'b
when 'a : not struct
and 'b : not struct> a b = obj.ReferenceEquals (a,b)
Run Code Online (Sandbox Code Playgroud)
它在F#2.0中运行良好,但产生:
警告FS1189:
类型参数必须直接放在类型名称旁边,例如"type C <'T>",而不是类型"C <'T>"
那么为运算符定义做出显式类型参数规范的正确方法是什么?
ps请不要告诉我隐式类型参数和其他一些解决方法,我想具体解决这个问题.
当我玩C#4.0动态时,我发现像这样的代码发生了奇怪的事情:
using System.Dynamic;
sealed class Foo : DynamicObject
{
public override bool TryInvoke(
InvokeBinder binder, object[] args, out object result)
{
result = new object();
return true;
}
static void Main()
{
dynamic foo = new Foo();
var t1 = foo(0);
var t2 = foo(0);
var t3 = foo(0);
var t4 = foo(0);
var t5 = foo(0);
}
}
Run Code Online (Sandbox Code Playgroud)
好的,它可以工作但是......看看IntelliTrace窗口:
截图http://img717.imageshack.us/img717/4914/10435230.png
因此,每次调用(以及动态对象上的其他操作)都会导致抛出和捕获奇怪的异常两次!
我理解,有时可以使用异常机制进行优化,例如,可以对某个存根委托执行对动态的第一次调用,这只会抛出异常 - 这可能就像是动态绑定器的信号来解析正确的成员并重新指向代表.下一次对同一代表的调用将在没有任何检查的情况下执行.
但是......上面代码的行为看起来很奇怪.也许每次对DynamicObject进行两次抛出和捕获异常 - 是一个错误?