[英]Why do I have to type-cast a strongly typed function using a dynamic input-parameter?
我有一個轉換器方法:
MyPoco Convert(dynamic p) => new MyPoco { A = p.X, B = p.Y };
void Test()
{
dynamic item = new { X = 1, Y = 2 };
var poco = (MyPoco)Convert(item);
}
我必須將結果明確地轉換為MyPoco,否則poco也將成為動態變量。
但是,如果我內聯Convert方法;
void Test()
{
MyPoco Convert(dynamic p) => new MyPoco { A = p.X, B = p.Y };
dynamic item = new { X = 1, Y = 2 };
var poco = Convert(item);
}
我不需要將ConvertItem轉換為MyPoco。 有這種現象的原因嗎? 編譯器應該很容易知道Convert return-type是MyPoco,對嗎?
它們之間存在差異,這可能是原因-局部函數不支持重載。 我認為這很重要-假設我們有兩個名稱相同,輸入和輸出類型不同的方法
static void Main(string[] args)
{
dynamic d = null;
var result = Hello(d);
Console.WriteLine("Hello World!");
}
static string Hello(string s)
{
return s;
}
static int Hello(int i)
{
return i;
}
這意味着結果可能是字符串或整數-我們在編譯時不知道。
而對於以下代碼,我們得到的錯誤是局部變量或函數已經聲明
static void Main(string[] args)
{
string Hello(string s)
{
return s;
}
int Hello(int s) // error - local variable or function with the same name already declared
{
return s;
}
dynamic d = null;
var result = Hello(d);
Console.WriteLine("Hello World!");
}
我們只能這樣寫
static void Main(string[] args)
{
string Hello(string s)
{
return s;
}
dynamic d = null;
var result = Hello(d);
Console.WriteLine("Hello World!");
}
因此,當編譯器看到本地Hello(...)調用時,它知道返回類型為字符串。
UPD:
關於編譯器在動態情況下推斷正確類型的能力。
我認為是的,編譯器可能會遇到這種情況-如果我們在編譯時知道只有一個方法,那么在運行時就不會出現另一個方法。
我可以想象,例如,我們調用的方法在另一個程序集中,並且在運行時加載了具有不同簽名的較新版本-動態可以使用,但是對於不帶重載的私有靜態方法,我認為我們可以推斷出非-動態類型。
但是我認為,為了簡單起見,決定以這種方式實現它-更容易記住簡單的規則-涉及動態的一切-動態。
為了簡化本地函數,我認為將它們動態化也將更加容易。 我認為這只是不同的人實施該方案的決定。
我檢查了roslyn源代碼,試圖找到有關此信息。
定義它的位置是Binder_Invocation.cs,BindMethodGroupInvocation方法。
對於局部函數,調用以下方法
private BoundExpression BindLocalFunctionInvocationWithDynamicArgument(
SyntaxNode syntax,
SyntaxNode expression,
string methodName,
BoundMethodGroup boundMethodGroup,
DiagnosticBag diagnostics,
CSharpSyntaxNode queryClause,
MethodGroupResolution resolution)
{
// Invocations of local functions with dynamic arguments don't need
// to be dispatched as dynamic invocations since they cannot be
// overloaded. Instead, we'll just emit a standard call with
// dynamic implicit conversions for any dynamic arguments. There
// are two exceptions: "params", and unconstructed generics. While
// implementing those cases with dynamic invocations is possible,
// we have decided the implementation complexity is not worth it.
// Refer to the comments below for the exact semantics.
如您所見,也有關於重載的說法,但是對於普通方法而言,沒有任何關於原因的信息
else
{
if (HasApplicableConditionalMethod(resolution.OverloadResolutionResult))
{
// warning CS1974: The dynamically dispatched call to method 'Goo' may fail at runtime
// because one or more applicable overloads are conditional methods
Error(diagnostics, ErrorCode.WRN_DynamicDispatchToConditionalMethod, syntax, methodGroup.Name);
}
// Note that the runtime binder may consider candidates that haven't passed compile-time final validation
// and an ambiguity error may be reported. Also additional checks are performed in runtime final validation
// that are not performed at compile-time.
// Only if the set of final applicable candidates is empty we know for sure the call will fail at runtime.
var finalApplicableCandidates = GetCandidatesPassingFinalValidation(syntax, resolution.OverloadResolutionResult,
methodGroup.ReceiverOpt,
methodGroup.TypeArgumentsOpt,
diagnostics);
if (finalApplicableCandidates.Length > 0)
{
result = BindDynamicInvocation(syntax, methodGroup, resolution.AnalyzedArguments, finalApplicableCandidates, diagnostics, queryClause);
}
else
{
result = CreateBadCall(syntax, methodGroup, methodGroup.ResultKind, analyzedArguments);
}
如果至少有一個候選人,他們會創造動態。 因此,正如我所說,我認為它可以是非動態的,但是實施它的人最初將其保持動態,可能是為了簡化。
為了找到更多細節,您可以做的是嘗試在沒有重載方法的情況下實現這種情況,更改代碼
if (finalApplicableCandidates.Length > 0)
{
result = BindDynamicInvocation(syntax, methodGroup, resolution.AnalyzedArguments, finalApplicableCandidates, diagnostics, queryClause);
}
通過添加Length == 1的檢查,然后調用BindInvocationExpressionContinued而不是BindDynamicInvocation並運行測試並檢查是否有失敗,也許有幫助(我什至沒有設法建立roslyn項目,dotnet核心有點奇怪)
PS
根據這個
if (boundMethodGroup.TypeArgumentsOpt.IsDefaultOrEmpty && localFunction.IsGenericMethod)
{
Error(diagnostics, ErrorCode.ERR_DynamicLocalFunctionTypeParameter, syntax, localFunction.Name);
return BindDynamicInvocation(
對於局部函數,我們可以獲取動態而不是具體類型。
如果您輸入這樣的內容
static void Main(string[] args)
{
int TestFunc<T>(T data)
{
return 1;
}
dynamic d = 2;
var r = TestFunc(d);
}
是的,它將給出錯誤,但是如果您檢查推斷的類型,則r會顯示動態))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.