วิธีการขยายต้องถูกกำหนดในคลาสที่ไม่ใช่แบบทั่วไป


213

ฉันได้รับข้อผิดพลาด:

วิธีการขยายต้องถูกกำหนดในคลาสที่ไม่ใช่แบบทั่วไป

ในบรรทัด:

public class LinqHelper

นี่คือคลาสตัวช่วยตามรหัส Mark Gavells ฉันสับสนจริง ๆ ว่าข้อผิดพลาดนี้หมายถึงอะไรเพราะฉันแน่ใจว่ามันทำงานได้ดีเมื่อฉันทิ้งไว้ในวันศุกร์!

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

/// <summary>
/// Helper methods for link
/// </summary>
public class LinqHelper
{
    public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property)
    {
        return ApplyOrder<T>(source, property, "OrderBy");
    }
    public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property)
    {
        return ApplyOrder<T>(source, property, "OrderByDescending");
    }
    public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property)
    {
        return ApplyOrder<T>(source, property, "ThenBy");
    }
    public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string property)
    {
        return ApplyOrder<T>(source, property, "ThenByDescending");
    }
    static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName)
    {
        string[] props = property.Split('.');
        Type type = typeof(T);
        ParameterExpression arg = Expression.Parameter(type, "x");
        Expression expr = arg;
        foreach (string prop in props)
        {
            // use reflection (not ComponentModel) to mirror LINQ
            PropertyInfo pi = type.GetProperty(prop);
            expr = Expression.Property(expr, pi);
            type = pi.PropertyType;
        }
        Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
        LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);

        object result = typeof(Queryable).GetMethods().Single(
                method => method.Name == methodName
                        && method.IsGenericMethodDefinition
                        && method.GetGenericArguments().Length == 2
                        && method.GetParameters().Length == 2)
                .MakeGenericMethod(typeof(T), type)
                .Invoke(null, new object[] { source, lambda });
        return (IOrderedQueryable<T>)result;
    }
}

คำตอบ:


309

เปลี่ยนแปลง

public class LinqHelper

ถึง

public static class LinqHelper

ประเด็นต่อไปนี้จะต้องได้รับการพิจารณาเมื่อสร้างวิธีการขยาย:

  1. ชั้นเรียนซึ่งได้กำหนดวิธีขยายต้องnon-generic, staticและnon-nested
  2. ทุกวิธีการขยายจะต้องเป็นstaticวิธีการ
  3. พารามิเตอร์แรกของวิธีการขยายควรใช้thisคำหลัก

หากคุณได้วางคลาสใน App_Code แล้วมันจะถูกผูกไว้กับคำหลักคงที่ในคำจำกัดความของคลาส แต่ถ้าคุณวางไว้ในโฟลเดอร์อื่น ๆ แล้วก็ดีที่จะใช้มันเป็นคลาสปกติ
DT

1
ในกรณีหนึ่งฉันได้ใช้public static class IQueryable<T> where T : MyBaseClassซึ่งสร้างข้อผิดพลาดนี้ด้วย where T : MyBaseClassวลีเป็นวิธีการของแต่ละบุคคลโดยไม่ได้<T>ในระดับคงที่
Bron Davies

1
แต่ถ้าชั้นเรียนเป็นบางส่วน? วิธีนี้ไม่ได้ผลสำหรับฉัน
Fandango68

1
ขอบคุณเพื่อนฉันติดพารามิเตอร์ "นี้"!
Roberto Gata

1
ระวังว่าคุณอาจได้รับคอมไพเลอร์นี้ถ้าคุณแปลงชั้นเรียนของคุณเป็นวิธีการเสริม (โดยอ้างอิงจากคอมไพเลอร์) ดูคำตอบนี้เกี่ยวกับวิธีการคงที่และคำตอบนี้เกี่ยวกับthisวิธีการขัดแย้ง
Maarten Bodewes

26

หากคุณไม่ต้องการมีฟังก์ชั่นแบบคงที่ให้กำจัดคำหลัก "this" ในอาร์กิวเมนต์


6
ฉันเกาหัวของฉันในขณะที่พยายามคิดออกว่าเหตุใด Visual Studio จึงคิดว่าฉันพยายามทำให้หนึ่งในคลาสของฉันเป็นวิธีการต่อขยาย ปรากฎว่าฉันมีthisคำหลักฝังอยู่ในลายเซ็นวิธีการของฉัน การลบมันล้างข้อผิดพลาด
Fütemire

20

เพิ่มคำหลักstaticให้กับการประกาศคลาส:

// this is a non-generic static class
public static class LinqHelper
{
}



15

วิธีแก้ปัญหาสำหรับผู้ที่พบปัญหาเช่นนาธาน:

คอมไพเลอร์ on-the-fly ดูเหมือนจะมีปัญหากับข้อผิดพลาดวิธีการส่วนขยายนี้ ... การเพิ่มstaticไม่ได้ช่วยฉันเช่นกัน

ฉันต้องการที่จะรู้ว่าสิ่งที่ทำให้เกิดข้อผิดพลาด?

แต่วิธีแก้ไขคือเขียนคลาส Extension ใหม่ (ไม่ซ้อนกัน) แม้ในไฟล์เดียวกันและสร้างใหม่

คิดว่ากระทู้นี้ได้รับมุมมองที่เพียงพอซึ่งเป็นวิธีการแก้ปัญหาที่ฉันพบ คนส่วนใหญ่อาจลองเพิ่ม 'คงที่' ก่อน google-ing เพื่อแก้ปัญหา! และฉันไม่เห็นวิธีแก้ไขปัญหานี้ที่อื่น


ฉันมีปัญหาเดียวกัน ฉันเพิ่งรู้ว่าฉันได้เพิ่มฟังก์ชั่นคงที่ภายในชั้นเรียนและลืมที่จะแสดงความคิดเห็นออก นั่นทำให้ชั้นเรียนของฉันคงที่ ตรวจสอบว่ามีวัตถุคงที่ในชั้นเรียนของคุณ
Mahesh

1

วิธีการขยายควรอยู่ในระดับคงที่ ดังนั้นโปรดเพิ่มวิธีการขยายของคุณภายในชั้นคงที่

ตัวอย่างเช่นมันควรเป็นแบบนี้

public static class myclass
    {
        public static Byte[] ToByteArray(this Stream stream)
        {
            Int32 length = stream.Length > Int32.MaxValue ? Int32.MaxValue : Convert.ToInt32(stream.Length);
            Byte[] buffer = new Byte[length];
            stream.Read(buffer, 0, length);
            return buffer;
        }

    }

สิ่งนี้แตกต่างจากคำตอบเมื่อหลายปีก่อนหรือไม่
Maarten Bodewes

1

ลองเปลี่ยนเป็นคลาสแบบคงที่และย้อนกลับ นั่นอาจช่วยแก้ปัญหาการมองเห็นในสตูดิโอเมื่อมันเป็นบวก


0

ฉันพบปัญหาที่คล้ายกันฉันสร้างโฟลเดอร์ 'foo' และสร้าง "class" ภายใน foo จากนั้นฉันได้รับข้อผิดพลาดดังกล่าว หนึ่งการแก้ไขคือการเพิ่ม "คงที่" ตามที่กล่าวไว้ก่อนหน้านี้ในชั้นเรียนซึ่งจะเป็น "สาธารณะคงที่ระดับ LinqHelper"

ข้อสันนิษฐานของฉันคือเมื่อคุณสร้างคลาสภายในโฟลเดอร์ foo จะถือว่าเป็นคลาสส่วนขยายดังนั้นกฎระหว่างอนึ่งต่อไปนี้จะนำไปใช้กับมัน:

1) ทุกวิธีการขยายจะต้องเป็นวิธีคงที่

การหลีกเลี่ยงปัญหาหากคุณไม่ต้องการให้เกิดไฟฟ้าสถิต วิธีแก้ปัญหาของฉันคือการสร้างคลาสโดยตรงภายใต้เนมสเปซแล้วลากไปยังโฟลเดอร์ "foo"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.