在fake IUnitOfWork接口的一个方法时,遇到了一个泛型问题,不知如何解决。
这个方法在接口中是这样定义的:
public interface IUnitOfWork : IDisposable { IQueryable<T> Set<T>() where T : class; }
希望在实现这个接口方法时,直接返回一个具体类型的实例。
尝试这样实现:
public class FakeUnitOfWork : IUnitOfWork { public IQueryable<T> Set<T>() where T : class { if (typeof(T) == typeof(AdUnit)) { return new List<AdUnit>().AsQueryable(); } else { throw new NotImplementedException(); } } }
编译出现下面的错误:
Error CS0266: Cannot implicitly convert type 'System.Linq.IQueryable<AdUnit>' to 'System.Linq.IQueryable<T>'. An explicit conversion exists (are you missing a cast?)
改为:
return new List<AdUnit>().AsQueryable<T>();
编译错误变为:
Error CS1929: 'List<AdUnit>' does not contain a definition for 'AsQueryable' and the best extension method overload 'Queryable.AsQueryable<T>(IEnumerable<T>)' requires a receiver of type 'IEnumerable<T>'
请问如何解决这个问题?
new List<AdUnit>() 是提问时的简化。实际场景下,List<AdUnit>()有一些初始化数据,代码如下:
public class FakeUnitOfWork : IUnitOfWork { private static List<AdUnit> _adUnits = new List<AdUnit>() { { new AdUnit { Id = "E1", Creatives = new Creative[] { new Creative { ImageSrc = "http://static.cnblogs.com/images/logo_small.gif", Url = "http://www.cnblogs.com/" } } } } }; public IQueryable<T> Set<T>() where T : class { if (typeof(T) == typeof(AdUnit)) { return _adUnits.AsQueryable(); } else { throw new NotImplementedException(); } } }
return new List<AdUnit>().AsQueryable(); 改为 return new List<T>().AsQueryable();
那就这样写:
return _adUnits.AsQueryable().Cast<T>();
.Cast<T>() 是更简单的正解
用dynamic也可以:
return new List<AdUnit>().AsQueryable() as dynamic;
@dudu: 嗯,不过这种方式感觉怪怪的!
@田园里的蟋蟀: 借助dynamic,可以这样实现:
FakeUnitOfWork:
public IQueryable<T> Set<T>() where T : class { if(typeof(T) == typeof(AdUnit)) { return AdUnitData.AdUnits; } else { throw new NotImplementedException(); } }
AdUnitData:
public class AdUnitData { private static List<AdUnit> _adUnits = new List<AdUnit>(); public static dynamic AdUnits { get { return _adUnits.AsQueryable(); } } }
@dudu: 嗯,好设计!
不过用dynamic,我总感觉有些怪怪的,比如这家伙会让你忽略类型,如果把AdUnitData改成下面的代码:
public class AdUnitData { private static List<AdUnitXXXXXX> _adUnits = new List<AdUnitXXXXXX>(); public static dynamic AdUnits { get { return _adUnits.AsQueryable(); } } }
编译是没有什么问题,但运行就会抛出异常。
@田园里的蟋蟀: 管它怪还是不怪,能有效地解决问题就行
@dudu: 嗯,确实能解决问题!
我想表达的是:尽量不要设置方法或属性返回类型为dynamic,因为调用方根本不清楚到底是什么类型,如果原类型修改了,编译也完全看不出来错误,既然AdUnitData已经确定类型为AdUnit,那返回dynamic就有点多余了。
同意楼上。
仍旧放 T 不用AdUnit
泛型的具体参数类型不应该在方法里确定,是在外部的时候确认的,这样不报错才怪。。
这样 return new List<T>().AsQueryable() 不能满足你的需求吗?
那就这样:
return (IQueryable<T>)new List<AdUnit>().AsQueryable();
经验证, (IQueryable<T>)new List<AdUnit>().AsQueryable(); 可行。
@dudu: 这样装箱真的好吗。。
@风晕: 本来就在箱子里
@dudu:没能理解..
public interface IUnitOfWork : IDisposable { IQueryable<T> Set<T>() where T : class; } public class AdUnit { } public class BaseUnitOfWork<T> : IUnitOfWork { public IQueryable<T> Set<T>() where T : class { return new List<T>().AsQueryable(); } public void Dispose() { throw new NotImplementedException(); } } public class FakeUnitOfWork : BaseUnitOfWork<AdUnit> { }
我觉得你想要的效果应该是这样的
if (typeof(T) == typeof(AdUnit)) { return (IQueryable<T>)_adUnits.AsQueryable(); } else { throw new NotImplementedException(); }
BaseUnitOfWork只能这样定义:
public class BaseUnitOfWork<T> : IUnitOfWork { public IQueryable<T1> Set<T1>() where T1 : class { throw new NotImplementedException(); } }
T1不能改为T
用1L的方法应该就妥了
直接泛型实现就不需要去转了,在外面具体调用不好多了
那里用T与你那个效果一样。为什么非要去直接写出来?但是返回值类型不匹配啊。