Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/266.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在c中模拟基于泛型返回类型的方法重载_C#_Generics - Fatal编程技术网

C# 如何在c中模拟基于泛型返回类型的方法重载

C# 如何在c中模拟基于泛型返回类型的方法重载,c#,generics,C#,Generics,我有一个读模型作为IQueryable,我在我的Web应用程序中使用它。很多时候我需要从这个阅读模型中提取不同的视图模型 我使用以下方式编写扩展方法: public static ViewModelA AsViewModelA(this IQueryable<CustomType> query) { var vm = view .Select(x => new ViewModelA {

我有一个读模型作为IQueryable,我在我的Web应用程序中使用它。很多时候我需要从这个阅读模型中提取不同的视图模型

我使用以下方式编写扩展方法:

public static ViewModelA AsViewModelA(this IQueryable<CustomType> query) 
{ 
    var vm = view
              .Select(x => new ViewModelA
              {
                  Something = x.Something
              }).FirstOrDefault();

    return vm;
}

public static ViewModelB AsViewModelB(this IQueryable<CustomType> query) 
{
    var vm = view
              .Select(x => new ViewModelB
              {
                  SomethingElse = x.SomethingElse
              }).FirstOrDefault();

    return vm;
}
这可以完成工作,但我不喜欢方法名产生的混乱;更通用的方式,类似这样的方式更可取:

query.AsViewModel<ViewModelA>()
我知道返回类型不打算用作方法签名,所以不会应用重载,并且我知道泛型类型不足以产生重载。 我想要的是一种基于泛型类型模拟重载的机制。这种机制应该避免使用带有级联if/then/else的main方法。有办法吗?可能使用dynamics?

是的,您可以使用dynamic:


只有当您在调用AsViewModel时经常发现自己必须使用泛型类型参数时,即当您事先不知道特定的“类型”时,我才会使用该选项。

一个选项是从该类型映射到CustomType到该类型的转换。所以它看起来像:


您可以使用更多的前端代码使字典结构更简洁。

TypeA是ViewModelA吗?在每种情况下,实现都是什么样子?@JonSkeet用实现更正了我是否应该避免这样的方法,而只是更改方法名称?@marianoc84:这取决于你。如果您只有其中的几个方法,那么使用多种方法是合理的。如果您有很多视图模型,那么这里的字典方法非常好——当然,它不会给您类型参数的编译时检查。
private static ViewModelA AsViewModelInternal(this IQueryable<CustomType> query, 
                                              ViewModelA dummy) { ... }

private static ViewModelB AsViewModelInternal(this IQueryable<CustomType> query, 
                                              ViewModelB dummy) { ... }

public static T AsViewModel<T>(this IQueryable<CustomType> query)
{
  return (T)query.AsViewModelInternal(default(T));
}
query.AsViewModelB()
query.AsViewModel<ViewModelB>()
private static readonly Dictionary<Type, Expression> Mappings = 
    new Dictionary<Type, Expression>
    {
        { typeof(ViewModelA),
          Helper<ViewModelA>(x => new ViewModelA { Something = x.Something }) },
        { typeof(ViewModelB),
          Helper<ViewModelB>(x => new ViewModelB { SomethingElse = x.SomethingElse }) },
        ...
    }

// This method just helps avoid casting all over the place.
// In C# 6 you could use an expression-bodied member - or add a 
private static Expression<Func<CustomType, T>> Helper<T>
    (Expression<Func<CustomType, T>> expression)
{
    return expression;
}

public static T AsViewModel<T>(this IQueryable<CustomType> query) 
{ 
    Expression rawMapping;
    if (!Mappings.TryGetValue(typeof(T), out rawMapping))
    {
        throw new InvalidOperationException("Or another exception...");
    }
    // This will always be valid if we've set up the dictionary properly
    var mapping = (Expression<Func<CustomType, T>>) rawMapping;
    return view.Select(mapping).FirstOrDefault();
}