在下面的代码中,为什么这两个string.Format调用的行为方式不一样?在第一个中,没有抛出任何异常,但在第二个ArgumentNullException抛出了一个异常.
static void Main(string[] args)
{
Exception e = null;
string msgOne = string.Format("An exception occurred: {0}", e);
string msgTwo = string.Format("Another exception occurred: {0}", null);
}
Run Code Online (Sandbox Code Playgroud)
有人可以帮我理解两者的区别吗?
考虑以下代码(它有点长,但希望你可以遵循):
class A
{
}
class B : A
{
}
class C
{
public virtual void Foo(B b)
{
Console.WriteLine("base.Foo(B)");
}
}
class D: C
{
public override void Foo(B b)
{
Console.WriteLine("Foo(B)");
}
public void Foo(A a)
{
Console.WriteLine("Foo(A)");
}
}
class Program
{
public static void Main()
{
B b = new B();
D d = new D ();
d.Foo(b);
}
}
Run Code Online (Sandbox Code Playgroud)
如果你认为这个程序的输出是"Foo(B)"那么你和我在同一条船上:完全错了!事实上,它输出"Foo(A)"
如果我从C类中删除虚方法,那么它按预期工作:"Foo(B)"是输出.
为什么编译器选择带有Awhen 的版本B是派生得更多的类?
这是一个关于为什么编译器在传递null文字作为参数时选择某个重载的问题,由string.Format重载证明.
ArgumentNullException当为args参数使用null literal时,string.Format会抛出一个.
string.Format("foo {0}", null);
Run Code Online (Sandbox Code Playgroud)
Format方法有一些重载.
string.Format(string, object);
string.Format(string, object[]);
string.Format(IFormatProvider, string, object[]);
Run Code Online (Sandbox Code Playgroud)
运行反编译代码,从第二个方法抛出null文字args的异常.但是,下面的示例调用上面的第一个方法(如预期的那样)然后调用第二个调用第三个方法最终返回"foo".
string x = null;
string.Format("foo {0}", x);
string y;
string.Format("foo {0}", y = null);
Run Code Online (Sandbox Code Playgroud)
但是string.Format("foo {0}", null)调用上面的第二个方法并导致null异常.为什么编译器在这种情况下决定null文字与第二个方法签名匹配而不是第一个?
下面的程序产生这个输出:
Foo<T> called
Process is terminated due to StackOverflowException.
Run Code Online (Sandbox Code Playgroud)
因此,Foo(baz)调用通用的Foo<T>,但Bar(baz)递归和并没有打电话Bar<T>.
我在C#5.0和Microsoft .NET上.当非泛型方法是一个时,编译器似乎选择泛型方法而不是递归override.
我在哪里可以找到这条规则的解释?(我猜想编译器会在两种情况下选择递归.)
以下是该计划的全部内容:
using System;
namespace ConsoleApplication1 {
class Baz { }
abstract class Parent {
public abstract void Foo(Baz baz);
}
class Child : Parent {
void Bar<T>(T baz) {
Console.WriteLine("Bar<T> called");
}
public void Bar(Baz baz) {
Bar(baz);
}
void Foo<T>(T baz) {
Console.WriteLine("Foo<T> called");
}
public override void Foo(Baz baz) {
Foo(baz);
} …Run Code Online (Sandbox Code Playgroud) 取消注释下面标记的行将导致堆栈溢出,因为重载解析有利于第二种方法.但是在第二种方法的循环中,代码路径采用第一次重载.
这里发生了什么?
private static void Main(string[] args) {
var items = new Object[] { null };
Test("test", items);
Console.ReadKey(true);
}
public static void Test(String name, Object val) {
Console.WriteLine(1);
}
public static void Test(String name, Object[] val) {
Console.WriteLine(2);
// Test(name, null); // uncommenting this line will cause a stackoverflow
foreach (var v in val) {
Test(name, v);
}
}
Run Code Online (Sandbox Code Playgroud) 这个问题再次引起了我的兴趣.有人可以提供技术解释,说明为什么以下代码不会产生任何警告或错误.你必须问自己的问题(当然)你感到幸运吗?
class Program
{
static string Feeling(object o) { return "Lucky"; }
static string Feeling(string s) { return "Unlucky"; }
static void Main(string[] args)
{
Console.WriteLine("I feel " + Feeling(null));
}
}
Run Code Online (Sandbox Code Playgroud)
如果您知道在不运行代码的情况下将调用哪种方法,则会获得奖励积分.只是为了添加侮辱,它不仅仅发生在null参数:
class Program
{
static string Feeling(int i) { return "Lucky"; }
static string Feeling(uint i) { return "Unlucky"; }
static void Main(string[] args)
{
Console.WriteLine("I feel " + Feeling(7));
}
}
Run Code Online (Sandbox Code Playgroud) 我有两个重载方法,如下所示
public class TestClass
{
public void LoadTest(object param)
{
Console.WriteLine("Loading object...");
}
public void LoadTest(string param)
{
Console.WriteLine("Loading string...");
}
}
Run Code Online (Sandbox Code Playgroud)
在调用此方法之后,它将显示输出为加载字符串...请解释.net如何处理此方案?
class Program
{
static void Main(string[] args)
{
var obj=new TestClass();
obj.LoadTest(null);
// obj.LoadType(null);
Console.ReadLine();
}
}
Run Code Online (Sandbox Code Playgroud) 我有多个重载方法.但我不能称之为正确的.如何告诉编译器我特别想要"这个方法"被称为"有这个参数"?
顽皮的方法是第二个:
public string Translate(string text, params object[] args)
{
// Blah blah blah...
}
public string Translate(string text, string category, params object[] args)
{
// Here we do some blah blah blah again...
}
Run Code Online (Sandbox Code Playgroud)
这里当我尝试调用第一个方法时:Translate("Hello {0} {1}", "Foo", "Bar");编译器假定我正在调用第二个方法并将参数设置为category = "Foo"和args = "Bar".
我试着在调用它们时命名参数,但它给了我一些编译器错误.
Translate("Hello {0} {1}", args: "Foo", "Bar"); // CS1738
Translate("Hello {0} {1}", args: "Foo", args: "Bar"); // CS1740
Run Code Online (Sandbox Code Playgroud)
我怎样才能做到这一点?
我最近发现了一个有趣的C#编译器行为.想象一下这样的界面:
public interface ILogger
{
void Info(string operation, string details = null);
void Info(string operation, object details = null);
}
Run Code Online (Sandbox Code Playgroud)
如果我们这样做
logger.Info("Create")
Run Code Online (Sandbox Code Playgroud)
编译器会抱怨他不知道选择哪个重载(不明确的调用......).似乎合乎逻辑,但是当你尝试这样做时:
logger.Info("Create", null)
Run Code Online (Sandbox Code Playgroud)
它突然没有麻烦,搞清楚null是一个字符串.此外,似乎找到正确的重载的行为已经随着时间的推移而改变,我发现旧代码中的错误在之前工作并且停止工作,因为编译器决定使用另一个重载.
所以我真的很想知道为什么C#在第二种情况下不会像第一种情况那样产生相同的错误.这样做似乎非常符合逻辑,但它尝试将其解析为随机重载.
PS我不认为提供这种模糊的界面是好的,不建议这样做,但遗产是遗留的,必须保持:)
考虑这个函数:
static void Throw<T>(string message) where T : Exception
{
throw (T)Activator.CreateInstance(typeof(T), message, (Exception)null);
}
Run Code Online (Sandbox Code Playgroud)
T正如问题标题所示,给定类型System.ArgumentException,我收到“找到不明确匹配”的运行时错误。查看 的文档ArgumentException,以下是公共构造函数:
ArgumentException()
ArgumentException(string)
ArgumentException(SerializationInfo, StreamingContext)
ArgumentException(string, Exception)
ArgumentException(string, string)
ArgumentException(string, string, Exception)
Run Code Online (Sandbox Code Playgroud)
鉴于我将 2 个参数传递给CreateInstance,并强制null为 null Exception,我很难理解为什么它与上面列表中的第四个构造函数不匹配?