Si le compilateur sait que certains token est une référence à un type donné (comme d'erreur CS0119 l'indique) et il sait que la destination de certains d'affectation (que ce soit un paramètre de la fonction, une variable ou quoi que ce soit) s'attend à une référence à un type donné, pourquoi ne peut pas le compilateur de le prendre comme un implicite typeof() appel?
Tout d'abord, votre proposition est que le compilateur raison à la fois "à l'intérieur à l'extérieur" et "l'extérieur vers l'intérieur" dans le même temps. C'est, pour faire de votre proposition de fonction, le compilateur doit à la fois en déduire que l'expression System.Text.Encoding
fait référence à un type et que le contexte, un appel à WriteFullName
-- nécessite un type. Comment savons-nous que le contexte n'exige une type? La résolution de l' WriteFullName
nécessite la résolution de surcharge car il pourrait y avoir une centaine d'entre eux, et peut-être que l'un d'entre eux prend un Type
comme un argument dans cette position.
Nous devons donc maintenant la surcharge de la conception de la résolution de reconnaître ce cas précis. Résolution de surcharge est assez dur déjà. Maintenant d'examiner les incidences sur l'inférence de type en tant que bien.
C# est conçu de telle sorte que, dans la grande majorité des cas, vous n'avez pas besoin de faire bidirectionnel inférence parce que bidirectionnel inférence est coûteux et difficile. L'endroit où nous faisons une utilisation bidirectionnelle inférence est lambdas, et il m'a pris la meilleure partie d'une année pour mettre en œuvre et de tester. L'obtention du contexte de l'inférence sur les lambdas a été un élément clé qui a été nécessaire pour faire LINQ travail et il a été vaut la très haute charge de la prise en bidirectionnel inférence de droit.
Par ailleurs: pourquoi est - Type
de spécial? Il est parfaitement légal de dire object x = typeof(T);
donc ne devrait pas object x = int;
être légal dans votre proposition? Supposons qu'un type C
a défini par l'utilisateur, la conversion implicite de Type
de C
; ne doit pas C c = string;
être légal?
Mais laissons cela de côté pour un moment et considérer le bien-fondé de votre proposition. Par exemple, ce que vous proposez-vous de faire à ce sujet?
class C {
public static string FullName = "Hello";
}
...
Type c = C;
Console.WriteLine(c.FullName); // "C"
Console.WriteLine(C.FullName); // "Hello"
N'est-ce pas vous frapper aussi bizarre que c == C
mais c.FullName != C.FullName
? Un principe de base du langage de programmation conception est que vous pouvez farcir une expression dans une variable et la valeur de la variable se comporte comme l'expression, mais ce n'est pas le cas ici.
Votre proposition est fondamentalement que chaque expression qui désigne un type a un comportement différent selon qu'il est utilisé ou remis, et c'est super déroutant.
Maintenant, vous pourriez dire, eh bien, nous allons faire une syntaxe spéciale pour lever l'ambiguïté des situations où le type est utilisé dans les cas où le genre est mentionné, et il ya une telle syntaxe. C'est - typeof(T)
! Si nous voulons traiter T.FullName
comme T
être Type
nous disons typeof(T).FullName
et si nous voulons traiter T
comme étant un qualificatif dans une recherche que nous disons T.FullName
, et maintenant nous avons propreté, de l'ambiguïté de ces cas, sans avoir à faire tout bidirectionnel d'inférence.
Fondamentalement, le problème fondamental est que les types ne sont pas de première classe en C#. Il y a des choses que vous pouvez faire avec les types que vous pouvez seulement le faire au moment de la compilation. Il n'y a pas:
Type t = b ? C : D;
List<t> l = new List<t>();
où l
est soit List<C>
ou List<D>
selon la valeur de b
. Depuis les types sont très expressions spéciales, et en particulier sont des expressions qui n'ont aucune valeur au moment de l'exécution , ils ont besoin d'une syntaxe particulière qui appelle quand ils sont utilisés en tant que valeur.
Enfin, il est aussi un argument pour être faites quant à l'exactitude. Si un développeur écrit Foo(Bar.Blah)
et Bar.Blah
est un type, les chances sont très bons, ils ont fait une erreur et a pensé qu' Bar.Blah
était une expression qui renvoie une valeur. Les cotes ne sont pas bonnes qu'ils ont l'intention de passer un Type
de Foo
.
Question de suivi:
pourquoi est-il possible avec la méthode des groupes lorsqu'ils sont passés à un délégué argument? Est-ce à cause de l'utilisation et de mentionner d'une méthode sont plus faciles à distinguer?
La méthode de groupes n'ont pas de membres; vous ne dites jamais:
class C { public void M() {} }
...
var x = C.M.Whatever;
parce qu' C.M
n'ont pas de membres de tous. Donc, ce problème disparaît. Nous ne disons jamais "eh bien, C.M
convertible en Action
et Action
a une méthode Invoke
alors laissons C.M.Invoke()
. Qui n'a tout simplement pas se produire. Encore une fois, la méthode des groupes ne sont pas de première classe, des valeurs. Seulement après, ils sont convertis aux délégués deviennent-elles des premières valeurs de classe.
Fondamentalement, la méthode des groupes sont traités comme des expressions qui ont une valeur , mais pas de type, puis la convertibilité des règles de déterminer quelle méthode les groupes sont convertibles à ce que délégué des types.
Maintenant, si vous allez faire de l'argument qu'une méthode de groupe doit être convertie implicitement MethodInfo
et utilisées dans un contexte où une MethodInfo
a été prévu, alors nous aurions à examiner le bien-fondé de ce. Il y a eu une proposition pour les décennies à faire une infoof
opérateur (prononcé "en foof" bien sûr!) qui retourne un MethodInfo
lorsque la méthode de groupe et un PropertyInfo
lors d'une propriété et ainsi de suite, et que cette proposition a toujours échoué, car trop de travail de conception pour trop peu d'avantages. nameof
était le prix bon marché à mettre en œuvre la version qui a été fait.
Une question que vous ne demandez pas, mais qui semble pertinente:
Vous avez dit qu' C.FullName
pourrait être ambigu, car il serait difficile de savoir si C
est Type
ou le type C
. Existe-il d'autres semblables à des ambiguïtés dans C#?
Oui! Considérer:
enum Color { Red }
class C {
public Color Color { get; private set; }
public void M(Color c) { }
public void N(String s) { }
public void O() {
M(Color.Red);
N(Color.ToString());
}
}
Dans ce scénario, habilement appelé la "Couleur" du Problème, le compilateur C# parvient à comprendre qu' Color
dans l'appel d' M
signifie que le type, et que, dans l'appel d' N
, cela signifie this.Color
. Faire une recherche dans la spécification sur la "Couleur" et vous trouverez la règle, ou de voir le post de blog de la Couleur de la Couleur.