使用泛型将类和方法名称动态传递给方法

时间:2014-02-23 08:12:02

标签: c# generics constraints

我想动态地将类名和方法名传递给方法并保持动态,我理解我应该使用泛型和可能的约束。

示例,我有一个班级

MemberRequestDTO    (contains several properties)

我还有一个名为

的方法
RecordsToRetrieve

使用一些反射我想要动态获取属性的值,我想出了如何做到这一点,但后来我意识到这是太硬的代码和紧密耦合,我想时间重构和创建一个具有使用具有约束的泛型的签名的方法。难以理解使用和约束等。

所以我想传入一个类名,并且能够在方法中使用它,并且我计划使用它反射:

Type type = typeof(classname);

我开始阅读和研究,我开始玩这样的代码:

public void GetTypeValues<T>() where T : class , new()
  1. 如何传递MemberRequestDTO的班级名称?
  2. Generic new for my?
  3. 如何将类名传递给parens()?
  4. 如果我使用它也会传递到parens?
  5. 我如何通过课程和方法?
  6. 阅读上述“其中T有约束(强制执行)属于”类AND AND new()?
  7. 对此有点迷茫和困惑,原谅我。

    编辑:

    基于答案和一些研究,我对此有了更多的了解:

    让我们忘记我试图传递一个方法,说我只想传递一个类

    假设具有属性的类看起来像这样

     public class MemberRequestDTO
     {
    
        public DateTime DateRequested { get; set; }
    
        public string FirstName { get; set; }
    
        public string LastName { get; set; }
      }
    

    然后我会新建这个

    var memberRequestDTO = new MemberRequestDTO();
    

    然后我想把它传递给一个通用的方法

    如何将对象的实例传递给泛型方法?那个签名怎么样,例子public void GetTypeValues()其中T:class,new()
    我想要有类和new()的约束吗?

    对于上面的内容,是T类的实例吗?因此,目的是我可以

    GetTypeValues(memberRequestDTO)      
    

    (这是我的实际问题,传入我实例化的任何类,并让方法“处理”处理该类,循环遍历属性并动态获取属性的名称值是的,它可能不会是一种无效的方法)

    是否应该在memberRequestDTO中传入引号或不引用?我希望能够将任何类的实例传递给成员,然后再操作它。 ()应该是吗? parens()应该为空还是包含类对象的泛型参数?

3 个答案:

答案 0 :(得分:0)

  

如何传递MemberRequestDTO的类名?

你已经拥有一个。在通用方法中,“Type parameter”在这种情况下T将是您感兴趣的类型的名称。

public void GetTypeValues<T>() where T : class , new()
{
    string typeName = typeof(T).Name;
}
  

Generic对我来说有什么新意?

这是一个禁令,它会阻止你在没有公共无参数构造函数的情况下传递任何类型。换句话说,它将允许您以“类型参数”

传入的新的类型
public void GetTypeValues<T>() where T : class , new()
{
    T instance = new T();//This is not possible without new constraint
}
  

如何将类名传递给parens()?

     

如果我使用它也会传递到parens?

不确定是什么parens()需要更多信息才能回答这个问题。

  

我如何传递课程和方法?

如果我理解正确“类型参数”T是您使用的运行时类型。所以你得到Type。我不确定你的课程是什么意思?无法传递类只能传递实例。

对于方法,有很多种方法。您可以传递MethodInfo或方法名称或A代理,或MethodCallExpression等。

  

阅读上面的“其中T有约束(强制执行)”   输入“class AND new()?

是。类约束阻止您传递值类型,new()约束允许您新建事物。​​

详细了解仿制品herehere

答案 1 :(得分:0)

以下是你的答案:

  1. GetTypeValues<MemberRequestDTO>()
  2. new()Type Parameter - T的约束。它表示类型参数T必须具有公共无参数构造函数。在您的情况下,MemberRequestDTO类必须是一个公共无参数构造函数,如下所示:

    public class MemberRequestDTO
    {
        public MemberRequestDTO() { ... }
    }
    
  3. 由于班级名称属于reference type,您可以将其作为type传递给parens,例如:SomeMethod(typeof(MemberRequestDTO));,其中方法的签名为void SomeMethod(Type type) { } }

  4. 如果您将该类作为type parameter传递给第(1)点,则它不会传递到parens()

  5. class约束意味着“类型参数必须是引用类型;这也适用于任何类,接口,委托或数组类型。” 和new()约束意味着“类型参数必须具有公共无参数构造函数。当与其他约束一起使用时,必须最后指定new()约束。”


  6. 编辑:

    如果我理解你的观点,那么泛型方法定义就像:

    public void GetTypeValues<T>(T typeObject) where T : class
    {
        // typeObject specific operations
    }
    

    动态使用typeObject,让“执行时编译器”执行类型推断以计算TSee the reference here.此外,imho,您在new ()处不需要T约束。

    之后,您可以将任何类的实例传递给此方法,如下所示:

    var memberRequestDTO = new MemberRequestDTO();
    GetTypeValues((dynamic) memberRequestDTO);
    

    编辑2:

    USAGE:使用反射动态获取类型值

    此方法将包含的属性值返回到IEnumerable<KeyValuePair<string, object>>

    public static IEnumerable<KeyValuePair<string, object>> GetTypeValues<T>(T typeObject) where T : class
    {
        // typeObject specific operations
        IEnumerable<KeyValuePair<string, object>> typeValues = 
            typeObject
            .GetType()
            .GetProperties()
            .Select(property => new KeyValuePair<string, object>(property.Name, property.GetValue(typeObject)));
        return typeValues;
    }
    

答案 2 :(得分:0)

我对你想做什么感到有点困惑,但我会试一试。我可以看到两种可能的解释,它们在调用者的开始和你想要实现的目标上有所不同。

解释#1:调用者开始知道该类的名称以及稍后想要调用的方法的名称,使用它手头的对象。这可以通过以下方式实现:

public Func<object, object> RecordMethod(string typeName, string methodName)
{
    var type = Type.GetType(typeName);
    var method = type.GetMethod(methodName);
    return (object o) => method.Invoke(o, new object[0]);
}

var method = RecordMethod("MemberRequestDTO", "RecordsToRetrieve");

// later that day ...
MemberRequestDTO someObj = ...;
var result = method.Invoke(someObj);

如果您需要动态处理类型名称和方法名称,这很好,例如来自用户输入。请注意,此方法需要始终使用object,并且只能使用不带参数的方法。还要注意,通过这种方式,类型不能保证具有无参数构造函数,因此调用者必须自己提供该对象。

解释#2:调用者开始知道实际的类和它想要稍后调用的实际方法,使用稍后可以构造的对象。这可以通过以下方式实现:

public Func<TOutput> CaptureMethod<TInput, TOutput>(Func<TInput, TOutput> method) 
where TInput : new()
{
    return () =>
    {
        var source = new TInput();
        return method(source);
    };
}

var capturedMethod = (MemberRequestDTO dto) => dto.RecordsToRetrieve();

// later that day ...
var result = capturedMethod();

它捕获一个已知方法并返回一个函数,该函数在被调用时将实例化您的类并在其上调用该方法。这是一种更静态的方法(调用者比前一个示例更了解)并且能够强制执行一个约束,使用的类型必须具有无参数构造函数。

我不知道我是否回答了你的问题,但至少应该给你一些想法。