【问题标题】:Merging generic method合并泛型方法
【发布时间】:2011-05-16 13:17:43
【问题描述】:

我是 C# 新手,我有以下 3 种方法。这些方法允许调用者通过在给定方法上指定 lambda 表达式来检索表的不同属性。但是,我感觉专家会将它们进一步组合成一个通用方法。如果可以的话,请告诉我怎么做。

private KeyValuePair<T, int> GetHeaderProperty<T>(Func<Header, T> Property, 
                                                  Source ds)
{
    Func<Source, Header> GetValue =
        a => Books.Where(str => str.BookId == a.DiscardBookId)
                 .First().Header;
    return new KeyValuePair<T,int>(Property(GetValue(ds)), 0);
} 

private KeyValuePair<T, int> GetBookProperty<T>(Func<Book, T> Property,
                                               Source ds)
{
    Func<Source, Book> GetValue = 
        a => Books.Where(str => str.BookId == a.DiscardBookId).First();

    return new KeyValuePair<T, int>(Property(GetValue(ds)), 0);
} 

private KeyValuePair<T, int> GetFleetProperty<T>(Func<Fleet, T> Property,
                                                 Source ds)
{
    Func<Source,Fleet> GetValue =
        a => Books.Where(str => str.BookId == a.DiscardBookId).First()
                 .Header.Fleet;

    return new KeyValuePair<T,int>(Property(GetValue(ds)), 0);
} 

【问题讨论】:

  • 专家会将它们进一步组合成一个通用方法:您想获得哪种结果?
  • 请调查我的解决方案

标签: c# generics lambda expression


【解决方案1】:

我认为下面将相当于连续调用所有三个方法并将结果添加到列表中:

private IEnumerable<KeyValuePair<T, int>> GetFleetProperty<T>(
                                              Func<Book, T> PropertyBook,
                                              Func<Header, T> PropertyHeader,
                                              Func<Fleet, T> PropertyFleet,
                                              Source ds)
{
    Func<Source,Fleet> GetValue =
        a => Books.Where(str => str.BookId == a.DiscardBookId).First();

    var book = GetValue(ds);
    var result = new List<KeyValuePair<T, int>>();
    result.Add(new KeyValuePair<T, int>(PropertyBook(book), 0);
    result.Add(new KeyValuePair<T, int>(PropertyHeader(book.Header), 0);
    result.Add(new KeyValuePair<T, int>(PropertyFleet(book.Header.Fleet), 0);
    return result;
} 

更新:
您还可以创建这样的方法:

private KeyValuePair<T, int> GetProperty<T, TProperty>(
                                 Func<TProperty, T> Property, 
                                 Func<Book, TProperty> GetProperty, 
                                 Source ds)
{
    Func<Source, Header> GetValue =
        a => Books.Where(str => str.BookId == a.DiscardBookId)
                 .First();
    var book = GetValue(ds);
    return new KeyValuePair<T,int>(Property(GetProperty(book)), 0);
} 

你可以这样称呼 Header:

GetProperty(xyz, b => b.Header, ds);

对于 Book,你可以这样称呼它:

GetProperty(xyz, b => b, ds);

对于 Fleet,您可以这样称呼它:

GetProperty(xyz, b => b.Header.Fleet, ds);

【讨论】:

  • 感谢 Daniel,我将多次调用这些方法中的每一个以在这些表中获取不同的属性,我真的不想一直返回列表。我知道我没有准确地解释这一点。例如,第一个方法可能被调用了 15 次,下一个方法被调用了 7 次,依此类推......
  • @Paul:那么,现在解释一下也许是个好主意?在您发表评论之后,完全不清楚应该如何合并这些方法。
  • 我只是在上面做了。每个方法都将在特定表上被调用多次...例如 Book、Header、Fleet 等...也许我尝试做的事情可能不只是可能...还是谢谢你看看跨度>
  • 太好了,这看起来像我想要的。我会运行它并让你知道.... 万分感谢 Paul
【解决方案2】:

你可以使用这样的东西

public interface IPieceProvider<T>
    {
        T GetPiece();
    }

    public class Fleet
    {
        public string Test;
    }

    public class Header
    {
        public Fleet Fleet;
        public string Test;
    }

    public class Source
    {
        public int DiscardBookId;
    }

    public partial class Book
        : IPieceProvider<Book>, IPieceProvider<Header>, IPieceProvider<Fleet>
    {
        public int BookId;
        public Header Header;
        public string Test;

        Book IPieceProvider<Book>.GetPiece()
        {
            return this;
        }

        Header IPieceProvider<Header>.GetPiece()
        {
            return Header;
        }

        Fleet IPieceProvider<Fleet>.GetPiece()
        {
            return Header.Fleet;
        }
    }

    class Program
    {
        Book[] Books;

        private KeyValuePair<T, int> GetProperty<T, TP>(Func<TP, T> propertyGetter, Source ds)
        {
            return Books
                .Where(b => b.BookId == ds.DiscardBookId)
                .Cast<IPieceProvider<TP>>()
                .Select(p => p.GetPiece())
                .Select(p => new KeyValuePair<T, int>(propertyGetter(p), 0))
                .First();
        }

        static void Main(string[] args)
        {
            var source = new Source();
            var prg = new Program();
            var bookTest = prg.GetProperty((Book b) => b.Test, source);
            var headerTest = prg.GetProperty((Header h) => h.Test, source);
            var fleetTest = prg.GetProperty((Fleet f) => f.Test, source);

            Console.ReadKey();
        }
    }

【讨论】:

  • 嗨 Viacheslav,这看起来真的很漂亮。我特别喜欢更简单的调用。干杯保罗
  • 嗨 Viacheslav,公共接口 IPieceProvider where T : Book, Header, Fleet { T GetPiece();不编译。类类型约束“UserQuery.Header”必须位于任何其他约束之前
  • 我发布了固定版本的示例,请尝试一下
  • 嗨 Viacheslav,我还没有尝试过代码,但我可以看到一个潜在的问题。 Book 已经定义,因为我使用了 linq to sql,它为实体 Book 提供了定义。考虑到这一点,您认为重新定义的 Book 会起作用吗?
  • 每个实体生成的类都标记为部分,您可以毫无问题地扩展它。我的代码被修改以反映这种变化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-30
  • 2011-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多