错误“扩展方法必须是静态的”是什么意思?

时间:2011-05-23 11:21:30

标签: c# .net linq extension-methods compiler-errors

我在这门课上遇到了麻烦,特别是方法:

public IQueryable<T> ExecuteOrderBys<T>(this IQueryable<T> source)

它说错误:

  

扩展方法必须是静态的

但是,当我将方法设为静态时,会抛出其他区域,特别是this.xxx无法在静态方法中访问。

我对使用<T>的返回类型和返回类型感到有点困惑,如果有人可以向我解释它以及它是如何工作的,我将不胜感激。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections;


/// <summary>
/// A collection of order bys
/// </summary>
public class OrderByCollection
{
    private ArrayList Orderings = new ArrayList();

    public int? Skip { get; set; }
    public int? Take { get; set; }

    public OrderByCollection()
    {
        // Default skip and takes to nulls so we know if they are set or not
        this.Skip = null;
        this.Take = null;
    }

    /// <summary>
    /// Add an order by to this collection
    /// </summary>
    public void AddOrderBy(string Field, bool Descending)
    {
        OrderByObj NewObj = new OrderByObj(Descending, Field);
        this.Orderings.Add(NewObj);
    }

    /// <summary>
    /// Executes the order bys
    /// </summary>
    public IQueryable<T> ExecuteOrderBys<T>(this IQueryable<T> source)
    {
        int ExecutionIndex = 0;
        foreach (OrderByObj O in this.Orderings)
        {
            if (ExecutionIndex == 0)
            {
                if (O.Descending)
                    source = LinqHelper.OrderByDescending(source, O.Field);
                else
                    source = LinqHelper.OrderBy(source, O.Field);
            }
            else
            {
                if (O.Descending)
                    source = LinqHelper.ThenByDescending((IOrderedQueryable<T>)source, O.Field);
                else
                    source = LinqHelper.ThenBy((IOrderedQueryable<T>)source, O.Field);
            }
            ExecutionIndex++;
        }

        // Skip and take
        if (this.Skip != null)
            source = source.Skip(this.Skip.Value);
        if (this.Take != null)
            source = source.Take(this.Take.Value);

        return (IOrderedQueryable<T>)source;
    }
}

修改

我正在尝试创建一个可以执行以下操作的类:

var q = db.tblJobHeaders;

OrderByCollection OBys = new OrderByCollection();
OBys.AddOrderBy("some field", true);
OBys.AddOrderBy("anotherfield", false);
OBys.ExecuteOrderBys(q);

8 个答案:

答案 0 :(得分:15)

您并不是试图通过示例的外观扩展IQueryable。从方法定义中删除this,您的示例应该可以正常工作。

public class OrderByCollection
{
    // .. shameless cut ..
    public IQueryable<T> ExecuteOrderBys<T>(IQueryable<T> source)
    {
        // .. we don't need no stinking body ..
    }
}

这将使您的示例有效:

var q = db.tblJobHeaders;

OrderByCollection OBys = new OrderByCollection();
OBys.AddOrderBy("some field", true);
OBys.AddOrderBy("anotherfield", false);
OBys.ExecuteOrderBys(q);

作为旁注,我不会使用bool来定义orderby的排序方式。代码不清楚。改为使用枚举或不同的方法:

OBys.AddOrderBy("some field", Sort.Ascending);

或:

OBys.AddOrderByDescending("some field");

更新

扩展方法用于将“插件”方法用于现有的类或接口。通过编写public IQueryable<T> ExecuteOrderBys<T>(this IQueryable<T> source),您确实应该将该方法挂钩到IQueryable<T>。因此应该像myQuery.ExecuteOrderBys一样访问它。

我的猜测是扩展方法必须是静态的并且包含在静态类中以避免混淆:

a)它们实际上不是类或接口的成员,除了公共字段/属性/方法之外,它们不能访问任何其他内容。

b)他们可以扩展任何课程。如果没有限制,您可以在名为DoSomething(this ThatObject instance)的类中调用方法ThatObject。问题是你不能访问公共接口以外的任何东西,因为它是一个扩展方法。

令人困惑的可能性是无穷无尽的;)

答案 1 :(得分:4)

使你的方法成为静态是正确的做法,使它成为一个扩展方法(使扩展方法成为或不做的事实是另一个辩论!)。

现在,由于您的方法是静态的,因此它被附加到定义它的,而不是此类的任何实例。这就是关键字this在这里毫无意义的原因。 this表示“类的当前实例”:根据定义,它不存在于静态方法中。

您需要引用的“this”只是输入参数source。将source放在this的位置,并确保您的代码将以所需的效果进行编译。

答案 2 :(得分:2)

扩展方法只能在静态类中定义为静态方法 - 这意味着您不能使用此类的任何实例变量 - 扩展方法的唯一依赖项应该是您传入的类型的实例和static / compile时间价值。

您的案例中的解决方法可能是将SkipTake定义为const(并为它们应用适当的常量值),或者将它们作为参数传递给您的扩展方法。

答案 3 :(得分:1)

扩展必须在静态类

中定义

试试这个:

public static class YourExtension
{
    public static IQueryable<T> ExecuteOrderBys<T>(this IQueryable<T> source)
    {
        // do something
    }
}

答案 4 :(得分:1)

public static class OrderByCollection
{
    // that's extension method
    // it should be static
    public static IQueryable<T> ExecuteOrderBys<T>(this IQueryable<T> source)
    {
    }
}

答案 5 :(得分:0)

将其更改为

public static class OrderByCollection

public static IQueryable<T> ExecuteOrderBys<T>(this IQueryable<T> source)

这里的关键问题是static关键字,它表示该类没有自己的任何状态,并且该方法不需要任何状态信息。

答案 6 :(得分:0)

您不应该通过this.xxx访问成员,您应该通过this ..变量访问它们。在这种情况下:来源 在使方法和包含它的类静态之后。

答案 7 :(得分:0)

首先,将您的集合类转换为泛型类,您需要这样做才能在扩展方法中使用IQueryable of T的类型推断:

public class OrderByCollection<T> 
{
    private List<T> Orderings = new List<T>();
    ...
}

然后声明一个包含扩展方法的新静态类。由于该方法是静态的,因此不能使用此限定符,而是将实例作为源参数传递:

public static class Extensions {
  public static IQueryable<T> ExecuteOrderBys<T>(this OrderByCollection<T> source) {
      // instead of this.xxx use source.xxx
      IQueryable<T> result;
      ...
      if (source.Skip != null)
        result = source.Skip(this.Skip.Value);
      if (source.Take != null)
        result = source.Take(this.Take.Value);
      ...
  } 
}