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

时间:2011-05-23 12:02:30

标签: c# generics inheritance

如果我有一个抽象类,有什么办法可以返回派生类类型的枚举器吗?或者我是否必须在基类或泛型方法中使用泛型?这是我正在尝试做的一个非常愚蠢的例子 -

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
}

然后我想在其他地方打电话

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
}

我知道我可以使用泛型方法(如Search<T>())来执行此操作,但我希望能够从一个不完全知道Person类型的类中调用搜索函数(例如, AJAX处理程序的基类)

如果无法做到这一点,任何人都可以给我一个例子或理由,为什么不呢?或者只是太难实现到编译器中?

5 个答案:

答案 0 :(得分:3)

没有理由不能使您的搜索方法具有通用性:

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;
    }
}

并致电programmer.Search<Programmer>()

MyType来自哪里?应该是Person吗?

答案 1 :(得分:3)

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

  

虚拟方法返回类型的协方差是一个相当频繁请求的功能,如果我拥有它,我会使用它。它从未成为标准,因为(1)CLR不支持它;我们必须在幕后生成大量的帮助代码才能使其工作,或者说服CLR团队改变(C ++ / CLI团队做了前者)(2)在大多数情况下你可以自己生成必要的辅助函数很容易只需创建一个具有正确返回类型的“新”方法,将其实现委托给虚方法,(3)Anders不认为它是一个特别重要的特性。 - 埃里克

所以,不,这是不可能的,是的,这是因为它太难了。

答案 2 :(得分:1)

如果您使用此“漂亮”用法搜索方法,我建议使用ExtensionMethod。使用Ext,您不必两次定义实体的有效类型。 programmer.Search<Programmer>() =&gt; 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;
        }
    }
}

答案 3 :(得分:1)

@ben dotnet:不必明确地传递有效类型的事实不是因为它是一种扩展方法。这是由于类型推断机制,并且也会出现在任何一种方法(扩展或常规)上。

在这样的方法原型中

public static IEnumerable<TType> Search<TType>(this TType row) : where TType : new(), Person
编译器已知

TType与行中出现的次数相同。因此,在调用方法时,知道programmer的类型就足以知道<...>之间的类型相同。这就是为什么我们可以省略它。如果没有以this关键字为前缀的参数,它也会起作用。

答案 4 :(得分:0)

您可以在基类中使用泛型类型,并在派生类中将泛型类型定义为派生类。

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>{}