How does type inference work with overloaded generic methods
I have these classes:
/* 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; }
}
Then I have two generic methods with this signature:
public TData Add<TData>(TData data)
where TData: Data
public TData Add<TData, TInfo>(TData data)
where TData: InfoData<TInfo>
where TInfo: InfoBase, IRelated
Now when I create an instance of Data
class and call Add
method
// data is of type Data
Add(data);
The first generic method is used and generic type Data
is correctly inferred.
But when I call the same method with a more implemented type object instance
// data is of type InfoData<ExtraInfo>
// ExtraInfo is of type InfoBase and implements IRelated
Add(data);
I would expect the second generic method to be invoked , but to my surprise it's not. If I check generic type constraints on the second one being:
where TData: InfoData<TInfo>
where TInfo: InfoBase, IRelated
The first one matches and the second one as well. And these types are more implemented than simple Data
type if that makes any difference.
Working example
Here is a working .Net Fiddle for you to play with.
Questions
Add
method so type inference would work and won't have to explicitly provide these types just to make sure that correct overload is being used? Edit
I've found the answer to my first question in MSDN documentation
The compiler can infer the type parameters based on the method arguments you pass in; it cannot infer the type parameters only from a constraint or return value.
In my case the first generic type can be inferred directly from parameter, but second one is more tricky. It can't be inferred from parameter only. Type constraint should be used, but compiler doesn't evaluate it.
I also have one possible solution to my second question that changes one type to concrete and keeps the other one generic.
public InfoData<TInfo> Add<TInfo>(InfoData<TInfo> data)
where TInfo: InfoBase, IRelated
But I'm wondering if there's a more general/generic way of mitigating around this problem so I can still keep both type parameters but somehow have both types as generic?
Assuming your Add methods are in the class named DataCollector; you can add extension method which accepts InfoData<ExtraInfo>
and returns the same type as shown below.
public static class DataCollectorExtensions
{
public static InfoData<ExtraInfo> AddInfoData(this DataCollector dataCollector, InfoData<ExtraInfo> data)
{
return dataCollector.Add<InfoData<ExtraInfo>, ExtraInfo>(data);
}
}
In this way you have to specify the generic parameters only once inside the extension method and use the extension method elsewhere without need to specify generic parameter.
new DataCollector().AddInfoData(new InfoData<ExtraInfo>());
You still have to name the method other than Add (I have named AddInfoData) otherwise compiler again picks up the public TData Add<TData>(TData data)
method in the the DataCollector class. As you're infact adding InfoData this method name should be acceptable. I suppose this solution should be acceptable for all practical purposes.
上一篇: 核心数据:删除实体的所有实例的最快捷方式
下一篇: 类型推理如何与重载泛型方法一起工作