简体   繁体   English

C#抽象类返回派生类型枚举器

[英]C# abstract class return derived type enumerator

If I have an abstract class, is there any way I can return an enumerator of the derived class's type? 如果我有一个抽象类,有什么办法可以返回派生类类型的枚举器? Or would I have to use generics in the base class, or a generic method? 或者我是否必须在基类或泛型方法中使用泛型? Here's a really dumbed down example of what I'm trying to do - 这是我正在尝试做的一个非常愚蠢的例子 -

public abstract class Person {
    public IEnumerable<MyType> Search() {
        DbDataReader reader = Database.Instance.ExecuteReader(sql);
        while(reader.Read()) {
            MyType row = new MyType();
            row.Load(reader);
            yeild return row;
        }
    }

    private Load(DbDataReader reader) {
        //load instance from reader row
    }

    //declare properties that can be searched, such as Location
}

public class Programmer : Person {
    //declare properties that can be searched, such as Language
}

Then somewhere else I'd like to be able to call 然后我想在其他地方打电话

Programmer programmer = new Programmer();
programmer.Location = "My city";
programmer.Language = "C#";
foreach(Programmer programmer in programmer.Search())
{
    //display list of c# programmers in my city
}

I know I can do this with a generic method, like Search<T>() , but I'd like to be able to call the search function from a class that does not know exactly type the Person is (for example, a base class for an AJAX handler) 我知道我可以用一般的方法来做这个,比如Search<T>() ,但我希望能够从一个不完全知道Person类型的类中调用搜索函数(例如,一个基类) AJAX处理程序的类)

If this cannot be done, can anyone give me an example or reason why not? 如果无法做到这一点,任何人都可以给我一个例子或理由为什么不呢? Or would it just be too hard to implement into the compiler? 或者只是太难实现编译器?

There's no reason you can't make your Search method generic: 没有理由你不能使你的搜索方法通用:

public IEnumerable<T> Search<T>() where T : MyType, new() {
    DbDataReader reader = Database.Instance.ExecuteReader(sql);
    while(reader.Read()) {
        T row = new T();
        row.Load(reader);
        yield return row;
    }
}

and call programmer.Search<Programmer>() . 并调用programmer.Search<Programmer>()

Where does MyType come from btw? MyType来自哪里? Should that be Person ? 那应该是Person吗?

See http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx

Covariance on virtual method return types is a fairly frequently requested feature, and I'd use it if I had it. 虚方法返回类型的协方差是一个相当频繁请求的功能,如果我有它,我会使用它。 It's never made the bar because (1) the CLR does not support it; 它从未成为标准,因为(1)CLR不支持它; we'd have to either generate lots of helper code behind the scenes to make it work, or convince the CLR team to change (the C++/CLI team did the former) (2) in most cases you can generate the necessary helper functions yourself quite easily; 我们必须在幕后生成大量的帮助代码才能使其工作,或者说服CLR团队改变(C ++ / CLI团队做了前者)(2)在大多数情况下你可以自己生成必要的辅助函数很容易 just make a "new" method that has the right return type that delegates its implementation to the virtual method, and (3) Anders does not consider it to be a particularly important feature. 只需创建一个具有正确返回类型的“新”方法,将其实现委托给虚方法,(3)Anders不认为它是一个特别重要的特性。 - Eric - 埃里克

So, No, it isn't possible, and YES, it's because it's too hard. 所以,不,这是不可能的,是的,这是因为它太难了。

If you search an approach with this "pretty" usage I propose an ExtensionMethod. 如果您使用这种“漂亮”用法搜索方法,我建议使用ExtensionMethod。 With an Ext you don't have to define the effective type of the Entity twice. 使用Ext,您不必两次定义实体的有效类型。 programmer.Search<Programmer>() => programmer.Search() programmer.Search<Programmer>() => programmer.Search()

public static PersonExtensions
{
    public static IEnumerable<TType> Search<TType>(this TType row) : where TType : new(), Person 
    {
        DbDataReader reader = Database.Instance.ExecuteReader(sql);
        while(reader.Read()) {
            var row = new TType()
            row.Load(reader);
            yeild return row;
        }
    }
}

@ben dotnet: the fact of not having to pass the effective type explicitely is not due to the fact that it's an extension method. @ben dotnet:没有必要明确地传递有效类型的事实并不是因为它是一个扩展方法。 It is due to the type inference mecanism and would occur as well on any kind of method (extension or regular). 这是由于类型推断机制,并且也会出现在任何一种方法(扩展或常规)上。

In such a method prototype 在这样的方法原型

public static IEnumerable<TType> Search<TType>(this TType row) : where TType : new(), Person

TType is known by the compiler to be the same the 4 times it occurs in the line. 编译器已知TType与行中出现的4次相同。 Thus, when calling the method it's enough to know the type of programmer to know that it will be the same type between the <...> . 因此,在调用方法时,知道programmer的类型就知道它将是<...>之间的相同类型就足够了。 That's why we can omit it. 这就是为什么我们可以省略它。 It works also if there is no parameter prefixed with the this keyword. 如果没有带this关键字前缀的参数,它也可以工作。

You could use a generic type in your base class and define your generic type in your derived class as the derived class. 您可以在基类中使用泛型类型,并在派生类中将泛型类型定义为派生类。

public abstract class Person<T> where T : Person<T>
    {
        public IEnumerable<T> Search()
        {
            DbDataReader reader = Database.Instance.ExecuteReader(sql);
            while (reader.Read())
            {
                var row = new T();
                row.Load(reader);
                yield return row;
            }
        }

        protected virtual void Load(DbDataReader reader){}
    }

    public class Programmer : Person<Programmer>{}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM