具有返回值类型推断(C#)的代理

时间:2009-05-12 14:17:14

标签: c# .net delegates type-inference

我还是代表们的新手,我一直在玩Steven John Metsker的“C#中的设计模式”一书中描述的基于代理的数据访问层(非常好的阅读!)。它定义了数据访问委托,如下所示:

public delegate object BorrowReader(IDataReader reader);

使用它的结果是看起来像其中之一的代码:

var result = Foo.Bar(new BorrowReader(DoFooBarMagic));
var result = Foo.Bar(DoFooBarMagic);

但是,由于委托的返回类型是“object”,因此需要强制转换以获取任何方法(本例中为“DoFooBarMagic”)才能返回。因此,如果“DoFooBarMagic”返回List,则需要执行以下操作:

var result = Foo.Bar(DoFooBarMagic) as List<string>;

我想要的是能够跳过强制转换,并从委托方法的返回类型推断出委托的返回类型。我的想法可能是有一种方法可以使用Type参数来推断返回类型。像这样的东西之一:

public delegate T BorrowReader<T>(IDataReader reader);
List<string> result = Foo.Bar(new BorrowReader(DoFooBarMagic)); 
//Look, Ma, no cast!
var result2 = Foo.Bar(DoFooBarMagic);

如果从委托方法的返回类型推断出返回的类型,但看起来不起作用。相反,你必须这样做:

public delegate T BorrowReader<T>(IDataReader reader);
var result = Foo.Bar(new BorrowReader<List<string>>(DoFooBarMagic));

这几乎不比演员更好。

那么有没有办法从委托方法的返回类型推断委托的返回类型?

编辑添加: 如果需要,我可以更改Foo.Bar的签名。目前的签名基本上是这样的:

public static T Bar<T>(string sprocName,
                       DbParameter[] params, 
                       BorrowReader<T> borrower);

注意:该签名是当前状态的结果,该状态使用此委托定义:

public delegate T BorrowReader<T>(IDataReader reader);

6 个答案:

答案 0 :(得分:6)

怎么样:

public static T Bar2<T>(Func<IDataReader,T> func) where T : class
{
    BorrowReader borrower = new BorrowReader(func);
    return (T) Foo.Bar(borrower);
}

我知道它仍在进行演员表演,这很难看,但它应该有效。 (我原本以为你可以从func隐式转换,但显然不是。至少在C#4.0之前没有。)

当然,如果您可以将Foo.Bar的签名更改为通用,那么您就是在笑......

编辑:回答评论:如果方法的签名被更改为采用通用委托,例如

public static T Bar<T>(Func<IDataReader, T> func)

然后调用代码可以几乎只是:

var result = Foo.Bar(DoFooBarMagic);

不幸的是,类型推断不适用于方法组,所以你必须使用:

Func<IDataReader, List<string>> func = DoFooBarMagic;
var result = Foo.Bar(func);

或(更好,如果略微效率低下)

var result = Foo.Bar(reader => DoFooBarMagic(reader));

所以你是对的 - 这个答案并没有让OP完全符合要求,但可能它已接近足以获得认可。希望这个编辑有助于解释其余部分:)

答案 1 :(得分:0)

这很难看,但你可以使用out参数。从我的枚举解析器:

public static T Parse<T>(string value)
{
    // return a value of type T
}

public static void Parse<T>(string value, out T eValue)
{
    // do something and set the out parameter
}

// now can be called via either
SomeEnum blah = Enums.Parse<SomeEnum>("blah");

// OR
SomeEnum blah;
Enums.Parse("blah", out blah);

第二个会推断出类型,但就像我说的那样,它很难看。

答案 2 :(得分:0)

不使用泛型。类型推断是一个编译时事件。一种解决方案是在您发布时拥有一个通用委托。通用委托会比演员更快。

答案 3 :(得分:0)

我认为没有办法绕过它。至少不是你提出的方式。主要的问题是,由于它必须在编译时被驱动,如果你没有显式的返回类型,那么编译器实际上不能推断返回类型。

答案 4 :(得分:0)

// if BorrowReader is generic...
public delegate T BorrowReader<T>(IDataReader reader);

public class Foo
{
    // ... and Foo.Bar() is also generic
    public static T Bar<T>(BorrowReader<T> borrower) { ... }

    public void SomeMethod()
    {
        // this does *not* work (compiler needs more help)
        var result1 = Foo.Bar(DoFooBarMagic);

        // but instead of this (which works)
        var result2 = Foo.Bar(new BorrowReader<List<string>>(DoFooBarMagic));

        // you can do this (also works)
        // which emits the same IL, anyway
        var result3 = Foo.Bar<List<string>>(DoFooBarMagic);
    }
}

答案 5 :(得分:0)

我希望F#可以做到这一点。我不是专家,但F#确实使用了返回类型类型推断(details on MSDN)。