C#:通过存储在字符串变量

时间:2018-09-22 07:45:54

标签: c# azure-cosmosdb

我想通过在字符串变量 refName 中拥有的名称来反映MVC项目的模型类。当前我正在使用switch case将那些类用作模板,即。我们如何更好地完成这一部分,以便如果有新类出现,那么我不想在此switch语句中插入新的大小写。

基本上,我要做的是根据 gRefType 字段将cosmos db中的数据收集为特定的模板类格式。这是我所做的:

IEnumerable<Object> itemsRefDetail;
switch (refName)
{
     case "AMCaseStatus":
         itemsRefDetail = await DocumentDBRepository<AMCaseStatus>.GetItemRefDetailAsync(p => p.GrefType == refName && p.Tag == tag, collectionId);
         break;
     case "AMcaseSubStatus":
         itemsRefDetail = await DocumentDBRepository<AMcaseSubStatus>.GetItemRefDetailAsync(p => p.GrefType == refName && p.Tag == tag, collectionId);
         break;
     case "AMRole":
         itemsRefDetail = await DocumentDBRepository<AMRole>.GetItemRefDetailAsync(p => p.GrefType == refName && p.Tag == tag, collectionId);
         break;
}

如上面的代码所示,每种情况下使用的Template类与case值相同。所有类都具有相同的属性(GrefType和Tag)。

这是DocumentDbRepository类:

public static class DocumentDBRepository<T> where T : class
{
    public static async Task<IEnumerable<T>> GetItemRefDetailAsync(Expression<Func<T, bool>> predicate, string collectionId)
    {
        IDocumentQuery<T> query = client.CreateDocumentQuery<T>(
            UriFactory.CreateDocumentCollectionUri(DatabaseId, collectionId))
            .Where(predicate)
            .AsDocumentQuery();

        FeedResponse<T> privilegeQueryResponse = await query.ExecuteNextAsync<T>();

        return privilegeQueryResponse;
    }
}

2 个答案:

答案 0 :(得分:1)

我举了一个如何反映泛型类型的示例,您唯一要做的就是将GrefTypeTag包装到基类/接口中。这可能会给您启动的机会:

  • BaseType是数据的基本类型,其中包含可以在lambda函数中使用的字段。
  • 数据是您的数据服务(client.CreateDocumentQuery),在这种情况下为一些测试数据。
  • DocumentDBRepository包含静态SelectData方法,该方法执行作为参数传递的lambda函数。
  • MyLookupThing源自用于反射的BaseType。
  • TestReflection执行反射并执行它。

代码如下:

// The basetype of an item (which contains de RefName etc)
public class BaseType
{
    public string RefName { get; set; }
    public string Tag { get; set; }
}

// static T service with some testdata (mock)
public static class Data<T> where T : BaseType
{
    public static List<T> MyData { get; } = new List<T>();

    static Data()
    {
        // create an item
        var item = Activator.CreateInstance<T>();
        item.RefName = "Test";
        item.Tag = "Bla";
        MyData.Add(item);

        var item2 = Activator.CreateInstance<T>();
        item2.RefName = "SomethingElse";
        item2.Tag = "TagThing";
        MyData.Add(item2);

        var item3 = Activator.CreateInstance<T>();
        item3.RefName = "Test2";
        item3.Tag = "Bla2";
        MyData.Add(item3);
    }
}

// the generic class which uses the basetype as generic
public static class DocumentDBRepository<T> where T : BaseType
{
    public static IEnumerable<T> SelectData(Func<T, bool> predicate)
    {
        // some static test data
        return Data<T>.MyData.Where(predicate);
    }
}

// your derived class from BaseType
public class MyLookupThing : BaseType
{

}

class TestReflection
{
    public TestReflection()
    {
        // you can create more classes derived from BaseType 
        var typeStr = "TestRef.MyLookupThing";

        // resolve the type:
        var lookupType = (from ass in AppDomain.CurrentDomain.GetAssemblies()
                          from t in ass.GetTypes()
                          where t.FullName == typeStr
                          select t).First();

        // get the type of the generic class
        var myType = typeof(DocumentDBRepository<>);

        // create a generic type
        var myGenericType = myType.MakeGenericType(lookupType);

        var method = myGenericType.GetMethod("SelectData", BindingFlags.Static | BindingFlags.Public);

        // Create the function (with the BaseType)
        var func = new Func<BaseType, bool>(item => item.RefName.StartsWith("Test"));

        // invoke the method of the generic class
        IEnumerable<BaseType> result = (IEnumerable<BaseType>)method.Invoke(null, new object[] { func });

        // show the results
        foreach (var item in result)
            Console.WriteLine(item.RefName);

        Console.ReadKey();
    }
}

哪个会给:

Test
Test2

结果

答案 1 :(得分:0)

在这里,您可以创建此表达式以将查询限制为以下类型:

internal static Expression<Func<TEntity, bool>> CreateTypeSpesificExpression<TEntity>(string refName) where TEntity : class
{
    var parameter = Expression.Parameter(typeof(IAmObject));
    var member = Expression.Property(parameter, nameof(IAmObject.GrefType));
    var contant = Expression.Constant(refName);
    var body = Expression.Equal(member, contant);
    var extra = Expression.Lambda<Func<TEntity, bool>>(body, parameter);
    return extra;
}

所有这些都假设您的AM类具有相同的接口。 完成后,您可以简单地将其添加到where子句中。

您的查询应如下所示:

IEnumerable<Object> itemsRefDetail = await DocumentDBRepository<AMCaseStatus>.GetItemRefDetailAsync(p => CreateTypeSpesificExpression(refName) && p.Tag == tag, collectionId);

还有一点需要指出的是,Cosmonaut已经对基于类型的集合共享提供了本机支持。