部分泛型类型在C#中推断可能吗? [英] Partial generic type inference possible in C#?

查看:104
本文介绍了部分泛型类型在C#中推断可能吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的工作我重写流利接口,用于我的IoC的类库,当我重构,以便共享通过一个基类的一些常见功能的一些code,我想出了一个障碍。

I am working on rewriting my fluent interface for my IoC class library, and when I refactored some code in order to share some common functionality through a base class, I hit upon a snag.

注意:这是我的希望的做的,不是我的有无的做。如果非要凑合着用不同的语法,我会的,但如果任何人有关于如何使我的code编译我想要的方式的想法,那将是非常受欢迎的。

Note: This is something I want to do, not something I have to do. If I have to make do with a different syntax, I will, but if anyone has an idea on how to make my code compile the way I want it, it would be most welcome.

我要一些扩​​展方法可用于一个特定基类,以及这些方法应该是通用的,用一个通用的类型,涉及的参数的方法中,但该方法也应该返回相关的特定类型特别是后代他们所调用的方法。

I want some extension methods to be available for a specific base-class, and these methods should be generic, with one generic type, related to an argument to the method, but the methods should also return a specific type related to the particular descendant they're invoked upon.

以比上面的描述记错一个$ C $℃实施例更好的

Better with a code example than the above description methinks.

下面是一个简单而完整的例子什么的的工作:

Here's a simple and complete example of what doesn't work:

using System;

namespace ConsoleApplication16
{
    public class ParameterizedRegistrationBase { }
    public class ConcreteTypeRegistration : ParameterizedRegistrationBase
    {
        public void SomethingConcrete() { }
    }
    public class DelegateRegistration : ParameterizedRegistrationBase
    {
        public void SomethingDelegated() { }
    }

    public static class Extensions
    {
        public static ParameterizedRegistrationBase Parameter<T>(
            this ParameterizedRegistrationBase p, string name, T value)
        {
            return p;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ConcreteTypeRegistration ct = new ConcreteTypeRegistration();
            ct
                .Parameter<int>("age", 20)
                .SomethingConcrete(); // <-- this is not available

            DelegateRegistration del = new DelegateRegistration();
            del
                .Parameter<int>("age", 20)
                .SomethingDelegated(); // <-- neither is this
        }
    }
}

如果你编译这个,你会得到:

If you compile this, you'll get:

'ConsoleApplication16.ParameterizedRegistrationBase' does not contain a definition for 'SomethingConcrete' and no extension method 'SomethingConcrete'...
'ConsoleApplication16.ParameterizedRegistrationBase' does not contain a definition for 'SomethingDelegated' and no extension method 'SomethingDelegated'...

我要的是为扩展方法(参数&LT; T&GT; )能够在两个被调用 ConcreteTypeRegistration DelegateRegistration ,并在这两种情况下的返回类型应该匹配扩展被调用的类型。

What I want is for the extension method (Parameter<T>) to be able to be invoked on both ConcreteTypeRegistration and DelegateRegistration, and in both cases the return type should match the type the extension was invoked on.

问题是如下:

我想这样写:

ct.Parameter<string>("name", "Lasse")
            ^------^
            notice only one generic argument

还以为参数&LT; T&GT; 返回它被调用上同一类型,这意味着一个对象:

but also that Parameter<T> returns an object of the same type it was invoked on, which means:

ct.Parameter<string>("name", "Lasse").SomethingConcrete();
^                                     ^-------+-------^
|                                             |
+---------------------------------------------+
   .SomethingConcrete comes from the object in "ct"
   which in this case is of type ConcreteTypeRegistration

有什么办法,我可以欺骗编译器得以实现这个飞跃吗?

Is there any way I can trick the compiler into making this leap for me?

如果我添加两个泛型类型参数的参数方法,类型推断强迫我要么同时提供,或根本没有,这意味着这样的:

If I add two generic type arguments to the Parameter method, type inference forces me to either provide both, or none, which means this:

public static TReg Parameter<TReg, T>(
    this TReg p, string name, T value)
    where TReg : ParameterizedRegistrationBase

给我这样的:

Using the generic method 'ConsoleApplication16.Extensions.Parameter<TReg,T>(TReg, string, T)' requires 2 type arguments
Using the generic method 'ConsoleApplication16.Extensions.Parameter<TReg,T>(TReg, string, T)' requires 2 type arguments

这是一样糟糕。

我可以很容易地进行重组的类,或者甚至通过将它们引入层级使方法的非扩展的方法,但我的问题是,如果我能避免重复的两个后代的方法中,并且在某些方式申报他们只有一次,为的基类。

I can easily restructure the classes, or even make the methods non-extension-methods by introducing them into the hierarchy, but my question is if I can avoid having to duplicate the methods for the two descendants, and in some way declare them only once, for the base class.

让我改的。有没有办法来改变类的第一个code上面的例子,因此,在主方法的语法可以保持,不会有问题复制方法是什么?

Let me rephrase that. Is there a way to change the classes in the first code example above, so that the syntax in the Main-method can be kept, without duplicating the methods in question?

在code将能够同时与C#3.0和4.0兼容。

The code will have to be compatible with both C# 3.0 and 4.0.

修改:我之所以宁愿不离开这两个泛型类型参数的推论是,对于一些服务,我要指定这是一种类型的构造函数参数的参数值,但传递这是一个后代的值。目前,指定的参数值和正确的构造函数调用匹配是同时使用的名称和参数的类型来完成的。

Edit: The reason I'd rather not leave both generic type arguments to inference is that for some services, I want to specify a parameter value for a constructor parameter that is of one type, but pass in a value that is a descendant. For the moment, matching of specified argument values and the correct constructor to call is done using both the name and the type of the argument.

让我举一个例子:

ServiceContainerBuilder.Register<ISomeService>(r => r
    .From(f => f.ConcreteType<FileService>(ct => ct
        .Parameter<Stream>("source", new FileStream(...)))));
                  ^--+---^               ^---+----^
                     |                       |
                     |                       +- has to be a descendant of Stream
                     |
                     +- has to match constructor of FileService

如果我离开既能类型推断,参数类型为的FileStream ,而不是

If I leave both to type inference, the parameter type will be FileStream, not Stream.

推荐答案

如果你只有两种特定类型的注册(这似乎是在你的问题的情况下),你可以简单地实现两个扩展方法:

If you have only two specific types of registration (which seems to be the case in your question), you could simply implement two extension methods:

public static DelegateRegistration Parameter<T>( 
   this DelegateRegistration p, string name, T value); 

public static ConcreteTypeRegistration Parameter<T>( 
   this ConcreteTypeRegistration p, string name, T value); 

那么你就不需要指定类型参数,所以类型推断将在你提到的例子工作。请注意,您可以用两个类型参数(一个在你的问题),同时实现的扩展方法只是代表团一个通用的扩展方法。

Then you wouldn't need to specify the type argument, so the type inference would work in the example you mentioned. Note that you can implement both of the extension methods just by delegation to a single generic extension method with two type parameters (the one in your question).

在一般情况下,C#不支持像 o.Foo&LT任何事情; INT,&GT;(..)来推断只有第二个类型参数(这将是不错的功能 - F#有它,它是非常有用:-))。你也许可以实现一个解决方法,它会让你写这(基本上,通过分离的呼叫分为两个方法调用,以获得可以应用的类型inferrence两处):

In general, C# doesn't support anything like o.Foo<int, ?>(..) to infer only the second type parameter (it would be nice feature - F# has it and it's quite useful :-)). You could probably implement a workaround that would allow you to write this (basically, by separating the call into two method calls, to get two places where the type inferrence can be applied):

FooTrick<int>().Apply(); // where Apply is a generic method

下面是一个伪code证明结构:

Here is a pseudo-code to demonstrate the structure:

// in the original object
FooImmediateWrapper<T> FooTrick<T>() { 
  return new FooImmediateWrapper<T> { InvokeOn = this; } 
}
// in the FooImmediateWrapper<T> class
(...) Apply<R>(arguments) { 
  this.InvokeOn.Foo<T, R>(arguments);
}

这篇关于部分泛型类型在C#中推断可能吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆