C# 如何可靠地确定在设计时使用var声明的变量的类型?

C# 如何可靠地确定在设计时使用var声明的变量的类型?,c#,reflection,appdomain,type-inference,C#,Reflection,Appdomain,Type Inference,我正在为C#in emacs开发一个完成(智能感知)设施 其思想是,如果用户键入一个片段,然后通过特定的击键组合请求完成,那么完成工具将使用.NET反射来确定可能的完成 这样做需要知道要完成的事情的类型。如果它是一个字符串,则有一组已知的可能方法和属性;如果它是一个Int32,它有一个单独的集合,依此类推 使用emacs中提供的代码lexer/parser包semantic,我可以找到变量声明及其类型。有鉴于此,使用反射获取类型的方法和属性,然后向用户显示选项列表是很简单的。(好的,在emacs

我正在为C#in emacs开发一个完成(智能感知)设施

其思想是,如果用户键入一个片段,然后通过特定的击键组合请求完成,那么完成工具将使用.NET反射来确定可能的完成

这样做需要知道要完成的事情的类型。如果它是一个字符串,则有一组已知的可能方法和属性;如果它是一个Int32,它有一个单独的集合,依此类推

使用emacs中提供的代码lexer/parser包semantic,我可以找到变量声明及其类型。有鉴于此,使用反射获取类型的方法和属性,然后向用户显示选项列表是很简单的。(好的,在emacs中执行不是很简单,但是使用,它变得简单多了。我编写了一个自定义的.NET程序集来执行反射,将其加载到powershell中,然后在emacs中运行的elisp可以通过comint向powershell发送命令并读取响应。因此,emacs可以快速获得反射的结果。)

当代码在正在完成的事情的声明中使用
var
时,问题就出现了。这意味着没有显式指定类型,完成将无法工作

使用
var
关键字声明变量时,如何可靠地确定实际使用的类型?我只是想说清楚,我不需要在运行时确定它。我想在“设计时”确定它

到目前为止,我有以下想法:

  • 编译并调用:
    • 提取声明语句,例如'var foo=“字符串值”`
    • 连接语句`foo.GetType()`
    • 动态编译生成的C#片段,并将其编译成新的程序集
    • 将程序集加载到新的AppDomain中,运行框架并获取返回类型
    • 卸载并丢弃部件
    我知道怎么做。但是对于编辑器中的每个完成请求,它听起来都非常重

    我想我并不每次都需要一个新的AppDomain。我可以将单个AppDomain重新用于多个临时程序集,并分摊设置它的成本 在多个完成请求中启动和拆除它。这更多的是对基本思想的调整。

  • 编译并检查IL 只需将声明编译成一个模块,然后检查IL,以确定编译器推断的实际类型。这怎么可能呢?我将使用什么来检查IL

  • 还有更好的主意吗?评论?建议


    编辑-进一步考虑,编译和调用是不可接受的,因为调用可能有副作用。因此,必须排除第一种选择

    另外,我认为我不能假设.NET4.0的存在


    更新-正确的答案(上文未提及,但Eric Lippert温和地指出)是实现一个全保真度类型推断系统。信息技术这是在设计时可靠确定var类型的唯一方法。但是,这也不容易做到。因为我没有幻想我想尝试构建这样一个东西,所以我选择了选项2的捷径——提取相关的声明代码,并编译它,然后检查生成的IL

    对于完成场景的一部分,这实际上是可行的

    例如,假设在以下代码片段中?是用户要求完成的位置。这项工作:

    var x = "hello there"; 
    x.?
    
    完成操作实现了x是一个字符串,并提供了适当的选项。它通过生成并编译以下源代码来实现这一点:

    namespace N1 {
      static class dmriiann5he { // randomly-generated class name
        static void M1 () {
           var x = "hello there"; 
        }
      }
    }
    
    …然后通过简单反射检查IL

    这也适用于:

    var x = new XmlDocument();
    x.? 
    
    引擎将适当的using子句添加到生成的源代码中,以便正确编译,然后IL检查也是一样的

    这也行得通:

    var x = "hello"; 
    var y = x.ToCharArray();    
    var z = y.?
    
    这只是意味着IL检查必须找到第三个局部变量的类型,而不是第一个

    这是:

    var foo = "Tra la la";
    var fred = new System.Collections.Generic.List<String>
        {
            foo,
            foo.Length.ToString()
        };
    var z = fred.Count;
    var x = z.?
    
    也不是LINQ语法

    我必须考虑这些东西的价值,在我考虑通过绝对的“有限设计”(有礼貌的黑客攻击)来解决这些问题之前。p> 解决依赖于方法参数或实例方法的问题的一种方法是,在生成、编译和分析的代码片段中,用相同类型的“合成”局部变量替换对这些对象的引用


    另一个更新-完成依赖于实例成员的变量,现在可以工作了

    我所做的是询问类型(通过语义),然后为所有现有成员生成合成替代成员。对于这样的C#缓冲区:

    public class CsharpCompletion
    {
        private static int PrivateStaticField1 = 17;
    
        string InstanceMethod1(int index)
        {
            ...lots of code here...
            return result;
        }
    
        public void Run(int count)
        {
            var foo = "this is a string";
            var fred = new System.Collections.Generic.List<String>
            {
                foo,
                foo.Length.ToString()
            };
            var z = fred.Count;
            var mmm = count + z + CsharpCompletion.PrivateStaticField1;
            var nnn = this.InstanceMethod1(mmm);
            var fff = nnn.?
    
            ...more code here...
    
    namespace Nsbwhi0rdami {
      class CsharpCompletion {
        private static int PrivateStaticField1 = default(int);
        string InstanceMethod1(int index) { return default(string); }
    
        void M0zpstti30f4 (int count) {
           var foo = "this is a string";
           var fred = new System.Collections.Generic.List<String> { foo, foo.Length.ToString() };
           var z = fred.Count;
           var mmm = count + z + CsharpCompletion.PrivateStaticField1;
           var nnn = this.InstanceMethod1(mmm);
          }
      }
    }
    
    public类csharp完成
    {
    私有静态int PrivateStaticField1=17;
    字符串InstanceMethod1(整数索引)
    {
    …这里有很多代码。。。
    返回结果;
    }
    公共无效运行(整数计数)
    {
    var foo=“这是一个字符串”;
    var fred=new System.Collections.Generic.List
    {
    福,
    foo.Length.ToString()
    };
    var z=fred.Count;
    var mmm=count+z+CsharpCompletion.PrivateStaticField1;
    var nnn=此.InstanceMethod1(mmm);
    变量fff=nnn。?
    …这里有更多代码。。。
    
    …编译生成的代码,以便我可以从输出IL中了解本地变量nnn的类型,如下所示:

    public class CsharpCompletion
    {
        private static int PrivateStaticField1 = 17;
    
        string InstanceMethod1(int index)
        {
            ...lots of code here...
            return result;
        }
    
        public void Run(int count)
        {
            var foo = "this is a string";
            var fred = new System.Collections.Generic.List<String>
            {
                foo,
                foo.Length.ToString()
            };
            var z = fred.Count;
            var mmm = count + z + CsharpCompletion.PrivateStaticField1;
            var nnn = this.InstanceMethod1(mmm);
            var fff = nnn.?
    
            ...more code here...
    
    namespace Nsbwhi0rdami {
      class CsharpCompletion {
        private static int PrivateStaticField1 = default(int);
        string InstanceMethod1(int index) { return default(string); }
    
        void M0zpstti30f4 (int count) {
           var foo = "this is a string";
           var fred = new System.Collections.Generic.List<String> { foo, foo.Length.ToString() };
           var z = fred.Count;
           var mmm = count + z + CsharpCompletion.PrivateStaticField1;
           var nnn = this.InstanceMethod1(mmm);
          }
      }
    }
    
    名称空间Nsbwhi0rdami{
    课程完成{
    private static int PrivateStaticField1=默认值(int);
    字符串InstanceMethod1(int索引){返回默认值(字符串);}
    无效M0zpstti30f4(整数计数){
    var foo=“这是一个字符串”;
    var fred=new System.Collections.Generic.L
    
    String x = "hello";
    var y = x.ToCharArray();
    var z = from foo in y where foo.
    
    var z = y.Where(foo=>foo.