我在我的基类中定义了一个抽象方法来接受Generic类型。我想要做的是将我的一个子类的列表传递给这个抽象方法。我只是不确定如何在子类中正确处理它?</ p>
基类抽象方法:
protected abstract void Validate<T>(T records);
子类实施(我遇到问题的地方):
调用方法(传入LogEventRecord列表):
Validate<List<LogEventRecord>>(records);
方法(想要处理LogEventRecord列表):
protected override void Validate<T>(T records)
{
//How do I handle records here? I want them to be List<LogEventRecord> and when i debug
//They appear to be coming in that way, but I can't utilize them in the method
//How do I cast the records to List<LogEventRecord>? Is that what I do?
}
任何建议都将不胜感激。
答案 0 :(得分:6)
听起来你的方法确实有错误的签名。参数名称为复数的事实,但它只是接受T
意味着。我怀疑它应该是:
protected abstract void Validate<T>(IEnumerable<T> records);
然后在您的实现中,您可以简单地迭代记录。话虽如此,如果您的子类只能验证LogEventRecord
的集合,那么真的应该使类型参数成为类的一部分,而不是方法的一部分:
public class Foo<T>
{
protected abstract void Validate(IEnumerable<T> records);
}
然后您的子类将是:
public class Bar : Foo<LogRecord>
{
protected override void Validate(IEnumerable<LogRecord> records)
{
foreach (LogRecord record in records)
{
...
}
}
}
如果没有更多的背景,很难知道这是否合适。如果它不立即适用,那么您可能需要更多地打破课程。
答案 1 :(得分:5)
声明这样的方法:
protected abstract void Validate<T>(IEnumerable<T> records)
并称之为:
Validate(records);
编译器应该能够推断泛型方法的类型,不需要明确地包含它。如果你真的想要包含类型或者由于某种原因类型推断失败(你会知道这是因为编译器会抱怨你),你可以这样做:
Validate<LogEventRecord>(records);
然后您的实现可以使用这样的记录:
protected override void Validate<T>(IEnumerable<T> records)
{
//you can use a foreach loop
foreach (T record in records)
{
}
//Or "linq" operators:
bool isValid = records.Any(r => r.IsNotValid);
//Or linq query comprehension syntax:
bool isValid2 = (from r in records
where r.IsNotValid
select r).Any();
}
但是现在你对T
唯一了解的是它是一个对象。对于“object”类型的变量,你不能做太多,所以这还不是很有用。实际上,我的示例中的后两个选项现在都会失败,因为.IsNotValid
属性可能不存在。
相反,您可能希望(可能已经有)一个接口来描述您将使用此函数的对象:它们可能总是要么是日志,要么是某些常见基类型的记录。如果是这种情况,您有两种选择。第一个是约束你的泛型类型。您可以通过更改方法签名来执行此操作:
protected abstract void Validate<T>(IEnumerable<T> records) where T : MyRecordInterface
另一个选择是在C#4中对接口的方差有新的支持(包括IEnumerabe&lt; T&gt;这将允许你完全避免使用泛型方法。为了利用这一点,只需确保您在Visual Studio 2010或更高版本中使用.Net 4并声明如下方法:
protected abstract void Validate(IEnumerable<MyRecordInterface> records)
您需要.Net 4,而不仅仅是针对早期版本的框架的c#4,因为您需要IEnumerable&lt; T&gt;的.Net 4版本。构建的接口包含对方差的必要支持。
最后,还有第三种选择。您可以在方法中添加delegate
参数,将列表中的每个项目转换为布尔值,如下所示:
protected abstract void Validate<T>(IEnumerable<T> records, Func<T, bool> isValid)
protected override void Validate<T>(IEnumerable<T> records, Func<T, bool> isValid)
{
bool recordsAreValid = records.Any(r => !isValid(r));
}
Validate(records, l => ((LogEventRecord)l).IsValid);
答案 2 :(得分:1)
明确使用列表通常对我有用。
protected override void Validate<T>(List<T> records)
在没有类型参数的情况下调用它,编译器会弄明白:Validate(records)