简体   繁体   English

如何编写通用扩展方法转换C#中的类型

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM