给出以下界面:
public interface IQuerySpec<M> { }
我很乐意制作这样的扩展方法:
public static OrderedSortation<T> OrderBy<T, TKey>(
this T query,
Expression<Func<T, TKey>> sort)
where T : IQuerySpec<?> {
//business as usual
}
我只是想确保T
类型是IQuerySpec<M>
的某种变体。然后,我可以按如下方式调用扩展方法:
public class Foo : IQuerySpec<int> {
public int SizeOfSailBoat {get; set;}
}
IQuerySpec<Foo> foo = new Foo {SizeOfSailBoat = 10}.
var result = foo.OrderBy(f => f.SizeOfSailBoat);
在上面的示例中指定了UDT Foo
,但我并不关心使用泛型类型参数。
有办法做到这一点吗?
我尝试了以下内容:
public static OrderedSortation<T> OrderBy<T, M, TKey>(
this T query,
Expression<Func<T, TKey>> sort)
where T : IQuerySpec<M> {
//business as usual
}
上述工作,但要求明确说明通用参数,以便调用&#34; OrderBy&#34;。我不希望被要求明确说明通用参数。
我也试过这个:
public interface IQuerySpec {}
public interface IQuerySpec<M> : IQuerySpec {}
通过这些界面,我可以这样做:
public static OrderedSortation<T> OrderBy<T, TKey>(
this T query,
Expression<Func<T, TKey>> sort)
where T : IQuerySpec {
//business as usual
}
这几乎已经足够了,除了我想要隐藏非泛型IQuerySpec,以便它在我的类库之外不可见。如果我能用这种方式限制非通用接口,我会很高兴:
internal interface IQuerySpec {}
不幸的是,编译器不允许我这样做。
我猜不出我想要的东西是不可能的,但要求以防万一。
答案 0 :(得分:0)
问题是编译器无法隐式地从M推断出M或T的类型。
所以你需要修复它们,在这里我将T修改为IQuerySpec<M>
并且扩展方法的签名变为
public static OrderedSortation<IQuerySpec<M>> OrderBy<M, TKey>(
this IQuerySpec<M> query,
Expression<Func<IQuerySpec<M>, TKey>> sort)
{
//business as usual
}
作为例子
class IntQSpec : IQuerySpec<int>
{
//your implementation
}
这是调用示例
var iQS = new IntQSpec();
//do whatever you want with iQS
var ord = iQS.OrderBy(ii=>ii.ToString());
//here I called OrderBy without the need to explicitly specifying the Generic Arguments
这是在visual studio 2013-2015上测试您的代码,突出显示没有错误
请注意我访问了混凝土类型IntQSpec
的Z字段
我希望它会有所帮助。
答案 1 :(得分:0)
在我看来,IQuerySpec<M>
根本就不需要IQuerySpec
或TKey
应始终M
根据我在这里看到的内容。我怀疑替换从而根据您IQuerySpec<M>
打开的愿望,根据IQuerySpec
取消M
。这是一个证据。请查看它是否符合您要完成的任务,或者是否可以采用最终解决方案的其中一个步骤:
假设事实上需要IQuerySpec<M>
且M
应始终等于TKey
,则以下编译并可能与您的实施有关:
假设TKey
为M
:
public interface IQuerySpec<M> { }
public class OrderedSortation<T> {}
public static class IQuerySpecExtensions
{
public static OrderedSortation<T> OrderBy<T, TKey>(this T query, System.Linq.Expressions.Expression<Func<T, TKey>> sort) where T : IQuerySpec<TKey>
{
throw new NotImplementedException(); // business as usual
}
}
public class Foo : IQuerySpec<int> { public int SizeOfSailBoat {get; set;} }
用法:
public class Demo
{
public static void Main()
{
Foo foo = new Foo {SizeOfSailBoat = 10};
var result = foo.OrderBy(f => f.SizeOfSailBoat);
}
}
假设需要多个TKey
选项:
如果您需要支持其他类型的其他属性(打开该类以获得更多查询可能性),那么您的类可能如下所示:
public interface IQuerySpec<M> { }
public class OrderedSortation<T> {}
public static class IQuerySpecExtensions
{
public static OrderedSortation<T> OrderBy<T, TKey>(this T query, System.Linq.Expressions.Expression<Func<T, TKey>> sort) where T : IQuerySpec<TKey>
{
throw new NotImplementedException(); // business as usual
}
}
public class Foo : IQuerySpec<int>, IQuerySpec<string>
{
public int SizeOfSailBoat {get; set;}
public string NameOfSailBoat {get; set;}
}
用法:
public class Demo
{
public static void Main()
{
Foo foo = new Foo {SizeOfSailBoat = 10};
var result = foo.OrderBy(f => f.SizeOfSailBoat);
result = foo.OrderBy(f => f.NameOfSailBoat);
}
}
将IQuerySpec<M>
缩减为IQuerySpec
:
在这种情况下,你可以简化为只有这样的IQuerySpec
:
public interface IQuerySpec { }
public class OrderedSortation<T> {}
public static class IQuerySpecExtensions
{
public static OrderedSortation<T> OrderBy<T, TKey>(this T query, System.Linq.Expressions.Expression<Func<T, TKey>> sort) where T : IQuerySpec
{
throw new NotImplementedException(); // business as usual
}
}
public class Foo : IQuerySpec
{
public int SizeOfSailBoat {get; set;}
public string NameOfSailBoat {get; set;}
}
用法:
public class Demo
{
public static void Main()
{
Foo foo = new Foo {SizeOfSailBoat = 10};
var result = foo.OrderBy(f => f.SizeOfSailBoat);
result = foo.OrderBy(f => f.NameOfSailBoat);
}
}
以上所有工作都禁止在IQuerySpec上定义没有引用M
的实际方法或属性签名。