代码之家  ›  专栏  ›  技术社区  ›  Ahmed

这是C 4中动态绑定的漏洞吗?

  •  5
  • Ahmed  · 技术社区  · 16 年前

    我看到了一个非常有趣的帖子 Fabio Maulo's 博客.如果您不想跳转到URL,这里是代码和bug。我这样定义了一个新的泛型类:

    public class TableStorageInitializer<TTableEntity> where TTableEntity : class, new()
        {
            public void Initialize()
            {
                InitializeInstance(new TTableEntity());
            }
    
            public void InitializeInstance(dynamic entity)
            {
                entity.PartitionKey = Guid.NewGuid().ToString();
                entity.RowKey = Guid.NewGuid().ToString();
            }
    
        }
    

    请注意,InitializeInstance接受一个动态类型的参数。现在为了测试这个类,我定义了另一个嵌套在主程序类中的类,如下所示:

    class Program
            {
                static void Main(string[] args)
                {
                   TableStorageInitializer<MyClass> x = new TableStorageInitializer<MyClass>();
                    x.Initialize();
                }
                private class MyClass
                {
                    public string PartitionKey { get; set; }
                    public string RowKey { get; set; }
                    public DateTime Timestamp { get; set; }
                }
            }
    

    注意:内部类“MyClass”被声明为私有。
    现在,如果我运行这个代码,我会得到一个 Microsoft.CSharp.RuntimeBinder.RuntimeBinderException 在“entity.partitionkey=guide.newguid().toString()”行上。
    不过,有趣的是,异常的消息说“对象不包含partitionkey的定义”。
    alt text http://img697.imageshack.us/img697/4188/testdl.png

    还要注意,如果将嵌套类的修饰符更改为public,代码将毫无问题地执行。你们觉得在引擎盖下到底发生了什么?请参考您可能发现的任何文档-当然,如果这是在任何地方记录的-您可以找到吗?

    1 回复  |  直到 16 年前
        1
  •  5
  •   Jon Skeet    16 年前

    活页夹试图算出 无障碍 类将对象视为-在本例中,进行调用的代码不“知道”有关 MyClass 类,所以它不“知道”关于 PartitionKey 或者。

    我不知道这在C 4规范中有多详细记录-我知道我已经和Chris Burrows通过电子邮件讨论过了,所以细节可能在某个地方 his blog :)请记住,动态绑定随着时间的推移而发生了变化,因此最近发布的文章对于RTM代码可能更准确。

    认为 如果你把 分区键 到私有类实现的公共接口中, 可以 工作-但你得试试。

    动态类型有各种各样的“gotchas”。显式接口实现也有类似的问题:

    public int Count(IList list)
    {
       int count1 = list.Count; // Fine
       dynamic d = list;
       int count2 = d.Count; // Should work, right?
    }
    

    如果传入数组,这将失败-因为尽管 IList.Count 存在,它是在数组中显式实现的-所以有点像这样:

    string[] array = new string[10];
    Console.WriteLine(array.Count); // Won't compile
    

    绑定器试图将对象视为其具体类型,而不是 IList 因此失败了…