Rob*_*nik 7 c# generics type-inference
我有这些课程:
/* Data classes */
public class Data
{
public int Id { get; set; }
}
public class InfoData<TInfo> : Data
where TInfo: InfoBase
{
public TInfo Info { get; set; }
}
/* Info classes */
public abstract class InfoBase
{
public int Id { get; set; }
}
public interface IRelated
{
IList<InfoBase> Related {get; set;}
}
public class ExtraInfo : InfoBase, IRelated
{
public string Extras { get; set; }
public IList<InfoBase> Related { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
然后我有两个这个签名的通用方法:
public TData Add<TData>(TData data)
where TData: Data
public TData Add<TData, TInfo>(TData data)
where TData: InfoData<TInfo>
where TInfo: InfoBase, IRelated
Run Code Online (Sandbox Code Playgroud)
现在,当我创建一个Data类和调用Add方法的实例时
// data is of type Data
Add(data);
Run Code Online (Sandbox Code Playgroud)
使用第一个泛型方法并Data正确推断泛型类型.
但是当我用更实现的类型对象实例调用相同的方法时
// data is of type InfoData<ExtraInfo>
// ExtraInfo is of type InfoBase and implements IRelated
Add(data);
Run Code Online (Sandbox Code Playgroud)
我希望可以调用第二个泛型方法,但令我惊讶的是它不是.如果我检查第二个上的泛型类型约束是:
where TData: InfoData<TInfo>
where TInfo: InfoBase, IRelated
Run Code Online (Sandbox Code Playgroud)
第一个匹配,第二个匹配.Data如果这有什么不同,这些类型比简单类型更实现.
这是一个有效的.Net小提琴供你玩.
Add方法,以便类型推断可以工作,并且不必显式提供这些类型只是为了确保正在使用正确的重载?我在MSDN文档中找到了第一个问题的答案
编译器可以根据您传入的方法参数推断类型参数; 它不能仅从约束或返回值推断类型参数.
在我的情况下,第一个泛型类型可以直接从参数推断,但第二个更棘手.它不能仅从参数中推断出来.应该使用类型约束,但编译器不会对其进行评估.
我也有一个可能的解决方案,我的第二个问题,将一种类型改为具体,并保持另一种通用.
public InfoData<TInfo> Add<TInfo>(InfoData<TInfo> data)
where TInfo: InfoBase, IRelated
Run Code Online (Sandbox Code Playgroud)
但我想知道是否有更通用/通用的方法来缓解这个问题所以我仍然可以保留两个类型参数,但不知何故两种类型都是通用的?
假设您的 Add 方法位于名为 DataCollector 的类中;您可以添加接受并返回相同类型的扩展方法,InfoData<ExtraInfo>如下所示。
public static class DataCollectorExtensions
{
public static InfoData<ExtraInfo> AddInfoData(this DataCollector dataCollector, InfoData<ExtraInfo> data)
{
return dataCollector.Add<InfoData<ExtraInfo>, ExtraInfo>(data);
}
}
Run Code Online (Sandbox Code Playgroud)
这样,您只需在扩展方法内指定一次泛型参数,并在其他地方使用扩展方法,而无需指定泛型参数。
new DataCollector().AddInfoData(new InfoData<ExtraInfo>());
Run Code Online (Sandbox Code Playgroud)
您仍然必须命名除 Add 之外的方法(我已命名为 AddInfoData),否则编译器会再次选择public TData Add<TData>(TData data)DataCollector 类中的方法。当您实际上添加 InfoData 时,该方法名称应该是可以接受的。我认为这个解决方案对于所有实际目的来说都是可以接受的。