扩展方法和动态对象

21 浏览
0 Comments

扩展方法和动态对象

我将把我的问题总结为以下代码片段。\n

List list = new List() { 5, 56, 2, 4, 63, 2 };
Console.WriteLine(list.First());

\n上述代码运行正常。\n现在我尝试了以下代码:\n

dynamic dList = list;
Console.WriteLine(dList.First());

\n但是我得到了RuntimeBinderException异常。为什么会这样呢?

0
0 Comments

扩展方法和动态对象

在使用下面的代码时,我们发现了一个问题:

List numbers = new List() { 1, 2, 3, 4, 5 };
int firstNumber = numbers.First();

上述代码中,我们试图使用`First()`方法获取列表`numbers`中的第一个元素。然而,编译器报错提示`First()`不是`List`的方法。事实上,`First()`方法是定义在Linq扩展方法中的,该扩展方法是针对`IEnumerable<>`接口定义的。

问题的原因是,虽然`List<>`类实现了`IEnumerable<>`接口,但它本身并没有定义`First()`方法。因此,在我们试图在`List<>`对象上调用`First()`方法时,编译器无法找到该方法的定义。

为了解决这个问题,我们可以使用扩展方法。扩展方法允许我们在不修改现有类的情况下,为其添加新的方法。在这种情况下,我们可以为`List<>`类添加一个扩展方法,使其具有`First()`方法的功能。下面是一个示例:

public static class MyExtensions
{
    public static T First(this List list)
    {
        if (list.Count > 0)
            return list[0];
        else
            throw new InvalidOperationException("List is empty.");
    }
}

在上面的代码中,我们定义了一个静态类`MyExtensions`,并在其中定义了一个名为`First()`的扩展方法。该方法接受一个泛型`List`作为参数,并返回列表中的第一个元素。如果列表为空,则抛出一个`InvalidOperationException`异常。

通过这种方式,我们就可以在`List<>`对象上调用`First()`方法了:

List numbers = new List() { 1, 2, 3, 4, 5 };
int firstNumber = numbers.First();

现在,我们可以成功地从`numbers`列表中获取第一个元素了。

通过使用扩展方法,我们可以在不修改现有类的情况下为其添加新的功能。这对于我们想要为已经存在的类添加一些自定义的方法非常有用。扩展方法在提高代码的可读性和可维护性方面也起到了积极的作用。

0
0 Comments

Extension methods are a powerful feature in C# that allow developers to add new methods to existing types without modifying the original code. However, when it comes to dynamic typing, extension methods are not supported in the form of extension methods. This means that extension methods cannot be called as if they were instance methods on dynamic objects.

To illustrate this, consider the following code snippet:

dynamic dList = list;
Console.WriteLine(Enumerable.First(dList));

In this example, a dynamic object `dList` is assigned a value of `list`. The `Enumerable.First` extension method is then called on `dList`. However, this will result in a runtime exception because extension methods cannot be directly called on dynamic objects.

One possible solution to this issue is to cast the dynamic object back to its known type before calling the extension method. This can be done by explicitly casting the dynamic object to the desired type:

Console.WriteLine(((List)dList).First());

Alternatively, the `as` operator can be used for the cast:

Console.WriteLine((dList as List).First());

By casting the dynamic object back to its known type, the extension method can be called successfully.

It is worth noting that the use of the `dynamic` keyword should be limited to cases where it is truly necessary, such as when accessing members with reflection. Using `dynamic` unnecessarily can lead to less readable and less maintainable code. Therefore, it is recommended to only use `dynamic` when there is a clear need for it.

In conclusion, the issue with using extension methods on dynamic objects arises from the lack of support for calling extension methods directly on dynamic objects. However, this can be resolved by casting the dynamic object back to its known type before calling the extension method. It is important to use the `dynamic` keyword judiciously and only when it is necessary to avoid potential issues and maintain code readability.

0
0 Comments

动态对象和扩展方法的问题产生的原因是,扩展方法在常规的非动态代码中通过对编译器已知的所有类进行完整搜索来工作,以查找具有匹配的扩展方法的静态类。搜索是根据命名空间嵌套和每个命名空间中可用的using指令的顺序进行的。因此,为了正确解析动态扩展方法调用,DLR在运行时必须以某种方式知道源代码中的所有命名空间嵌套和using指令。然而,我们目前没有一个机制将所有这些信息编码到调用点中。我们曾考虑过发明这样一个机制,但认为成本太高,而且产生的进度风险太大,不值得这样做。

是否计划实现这个功能?不,不计划。是否存在安全风险?我不知道有什么风险;你考虑的是什么样的安全风险?首先要说清楚攻击者是谁,以及他们对用户造成了什么威胁。

另外,我已经了解到所有的dynamic对象在C#中都等同于DynamicObject,所以无法区分它们是不能给dynamic添加扩展方法的原因之一,对吗?

请考虑扩展这个回答,加上类似于“当任何参数都是dynamic时,所有的解析都被推迟到运行时”的句子。虽然对你来说这一重要点是显而易见的,但在其他地方很难找到类似的解释(例如,参见stackoverflow.com/questions/48324768/)。

尽管完全有效,但这一点与本问题无关,本问题只是关于扩展方法的狭义问题。如果你认为有必要在SO上有一个包含你提到的信息的规范答案,并且没有现有的问题符合条件,我建议你发布一个新问题,专门解决这种情况。

也就是说,我不明白你为什么认为这一点还没有得到充分的解答。stackoverflow.com/questions/14185990/... 这个问题就是一个例子。还有stackoverflow.com/questions/9382130/...。

我知道有足够的解释(我自己也可以找到答案),我的担心是其他人不太可能将“一个参数作为dynamic传递”和整个调用变为运行时的联系联系起来。如果我不知道答案,我不知道如何从“C#扩展动态”或“C#扩展C1973”这样的问题导向这个答案和你链接的答案。

0