允许派生类型转换为父类型返回' object ',但使用派生类型's方法
本文关键字:派生 类型 object 方法 返回 许派生 类型转换 父类 | 更新日期: 2023-09-27 17:52:52
给出以下代码(我知道这不会编译并且是不正确的):
public abstract class Fetcher {
public abstract IEnumerable<object> Fetch();
}
public class Fetcher<T> : Fetcher {
private readonly Func<IEnumerable<T>> _fetcher;
public Fetcher(Func<IEnumerable<T>> fetcher) { _fetcher = fetcher; }
public IEnumerable<T> Fetch() => _fetcher(); // override or new
}
下面的示例设置:
var myFetchers = new List<Fetcher> {
new Fetcher<string>(() => new List<string> { "white", "black" })),
new Fetcher<int>(() => new List<int> { 1, 2 }))
};
我如何构建我的代码,使其工作?
IEnumerable<IEnumerable<object>> fetcherResults =
myFetchers.Select(fetcher => fetcher.Fetch()); // get objects from derived method
TLDR;我再考虑了一下。陈述我的问题的另一种方式是:我如何在myFetchers
列表中的所有项目上运行Fetch
方法并保存其结果的集合,而不必确定每个项目的基本类型并将其转换为该类型,同时不从Fetch
方法本身返回IEnumerable<object>
?
这里的关键是,当不同泛型类型的对象在父类型的集合中时,我想运行派生类型的方法,但返回结果为IEnumerable<object>
,而不是IEnumerable<T>
。(我想,如果有必要的话,可以使用不同的方法来完成,不过如果使用相同的名称就更好了。)这样,一段不需要知道抓取器的代码就可以拥有它的数据(只需要传递fetcherResults
),但是关心抓取器的那部分代码可以完全忽略抓取器处理的数据类型(不是它的关注点,只有数据的消费者需要处理特定类型)。
我不需要在这里使用继承,接口IFetcher
也可以工作得很好。我一直在想显式接口实现可能会有什么帮助,但我现在还没有结束这个循环,如何为我工作:
// in a class implementing ICollection<T>
public IEnumerator<T> GetEnumerator() => _collection.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable) _collection).GetEnumerator();
与往常一样,实际情况比这更复杂(例如,获取器提供的数据来自数据库等)。但是把这一部分写下来就足够了。
我看了下面的资源都没有用:实现一个可继承的方法,返回一个对象,从抽象父类调用泛型类型的方法。
正如您所怀疑的那样,有一种直接的方法可以通过显式实现来做到这一点。这只有在使用接口而不是抽象类时才可用。
public interface IFetcher {
IEnumerable<object> Fetch();
}
public class Fetcher<T> : IFetcher {
private readonly Func<IEnumerable<T>> _fetcher;
public Fetcher(Func<IEnumerable<T>> fetcher) { _fetcher = fetcher; }
IEnumerable<object> IFetcher.Fetch() => Fetch().Cast<object>();
public IEnumerable<T> Fetch() => _fetcher();
}
在这个实现中,调用的接口版本返回IEnumerable<object>
,而类可访问版本返回更具体的IEnumerable<T>
。如果通过接口调用获取器,它将解析为第一个。通过类调用将解析为第二个。
如果我正确理解问题,那么您可以通过使Fetcher<T>
实现IFetcher<T>
这样的通用接口来解决问题:
public interface IFetcher<T>
{
IEnumerable<T> Fetch();
}
public class Fetcher<T> : IFetcher<T>
{
private readonly Func<IEnumerable<T>> _fetcher;
public Fetcher(Func<IEnumerable<T>> fetcher) { _fetcher = fetcher; }
public IEnumerable<T> Fetch() => _fetcher();
}
然后创建一个适配器,可以将IFetcher<TFrom>
转换为IFetcher<TTo>
,如下所示:
public class Adaptor<TFrom, TTo> : IFetcher<TTo>
{
private readonly IFetcher<TFrom> _fetcher;
public Adaptor(IFetcher<TFrom> fetcher)
{
_fetcher = fetcher;
}
public IEnumerable<TTo> Fetch()
{
return _fetcher.Fetch().Cast<TTo>();
}
}
这允许从IFetcher<string>
转换为IFetcher<object>
。
public static class ExtensionMethods
{
public static Converter<TFrom> Convert<TFrom>(this IFetcher<TFrom> fetcher)
{
return new Converter<TFrom>(fetcher);
}
public class Converter<TFrom>
{
private readonly IFetcher<TFrom> _fetcher;
public Converter(IFetcher<TFrom> fetcher)
{
_fetcher = fetcher;
}
public IFetcher<TTo> To<TTo>()
{
return new Adaptor<TFrom, TTo>(_fetcher);
}
}
}
你可以很容易地这样做:
static void Main(string[] args)
{
var myFetchers = new List<IFetcher<object>>
{
new Fetcher<string>(() => new List<string> { "white", "black" }).Convert().To<object>(),
new Fetcher<int>(() => new List<int> { 1, 2 }).Convert().To<object>()
};
var results = myFetchers.Select(x => x.Fetch());
}
请注意,您可以不使用扩展方法,但它会使您的代码更具可读性。