[英]How to Write Generic Extension Method to Convert Type in C#
I am writing a static guard class/api to validate parameters sent to methods. 我正在编写一个静态防护类/ api来验证发送给方法的参数。
Code so far looks like: 到目前为止的代码如下:
public static class Guard
{
public static GuardArgument<T> Ensure<T>(T value, string argumentName)
{
return new GuardArgument<T>(value, argumentName);
}
public static T Value<T>(this GuardArgument<T> guardArgument)
{
return guardArgument.Value;
}
// Example extension method
public static GuardArgument<T> IsNotNull<T>(this GuardArgument<T> guardArgument, string errorMessage)
{
if (guardArgument.Value == null)
{
throw new ArgumentNullException(guardArgument.Name, errorMessage);
}
return guardArgument;
}
}
It can be used as so: 它可以这样使用:
public void Test(IFoo foo) {
Guard.Ensure(foo, "foo").IsNotNull();
}
Circumstances now require that I need to cast to concrete types from a supplied interface. 现在的情况要求我需要从提供的界面转换为具体类型。 Don't ask why, I just need to! 不要问为什么,我只需要!
I want to add an As
extension method to GuardArgument
to do this, something like: 我想为GuardArgument
添加一个As
扩展方法来执行此操作,例如:
public static GuardArgument<TOut> As<TOut, TIn>(this GuardArgument<TIn> guardArgument, Type type)
where TOut : class
{
// Check cast is OK, otherwise throw exception
return new GuardArgument<TOut>(guardArgument.Value as TOut, guardArgument.Name);
}
I don't much like the syntax though. 我不太喜欢这种语法。 I want to be able to use the class as follows: 我希望能够使用如下类:
Foo foo = Guard.Ensure(foo, "foo")
.As(typeof(Foo))
.IsNotNull()
.Value();
I'm not sure how to write the extension method to allow this syntax though. 我不知道如何编写扩展方法来允许这种语法。 I realise I can use the existing fluent API as: 我意识到我可以使用现有的流畅API:
Foo foo = Guard.Ensure(foo as Foo, "foo")
.IsNotNull()
.Value();
but I don't like this from a readability perspective. 但从可读性的角度来看,我不喜欢这个。
You can get this syntax: 你可以得到这样的语法:
Foo foo = Guard.Ensure(foo, "foo")
.As<Foo>()
.IsNotNull()
.Value();
The trick is to ditch the TIn
type param. 诀窍是TIn
类型的参数。 It's not used in the As()
method and bloats the API when type inference can't be used due to TOut
. 它不会在As()
方法中使用,并且As()
TOut而无法使用类型推断时会使API TOut
。 To be able to do that without getting As()
suggested on all types you have to implement a new, non-generic interface for your GuardArgument<>
class: 为了能够在不获得所有类型的As()
情况下执行此操作,您GuardArgument<>
为GuardArgument<>
类实现一个新的非泛型接口:
interface IGuardArgument
{
object Value { get; }
strign Name { get; }
}
public class GuardArgument<T> : IGuardArgument
{
// Explicit implementation to hide this property from
// intellisense.
object IGuardArgument.Value { get { return Value; }
// Rest of class here, including public properties Value and Name.
}
Now you can write the As()
method with only one generic param: 现在,您可以只使用一个通用参数编写As()
方法:
public static GuardArgument<TOut> As<TOut>(this IGuardArgument guardArgument)
where TOut : class
{
// Check cast is OK, otherwise throw exception
return new GuardArgument<TOut>(guardArgument.Value as TOut, guardArgument.Name);
}
Introduce an IGuardArgument interface which GuardArgument{T} implements. 介绍GuardArgument {T}实现的IGuardArgument接口。 Then you can remove TIn from the As extension method and remove the Type parameter. 然后,您可以从As扩展方法中删除TIn并删除Type参数。 Signature: 签名:
public static GuardArgument<TOut> As(this IGuardArgument guardArgument);
Usage: 用法:
Guard.Ensure(foo, "foo").As<Foo>().IsNotNull()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.