我想动态地将类名和方法名传递给方法并保持动态,我理解我应该使用泛型和可能的约束。
示例,我有一个班级
MemberRequestDTO (contains several properties)
我还有一个名为
的方法RecordsToRetrieve
使用一些反射我想要动态获取属性的值,我想出了如何做到这一点,但后来我意识到这是太硬的代码和紧密耦合,我想时间重构和创建一个具有使用具有约束的泛型的签名的方法。难以理解使用和约束等。
所以我想传入一个类名,并且能够在方法中使用它,并且我计划使用它反射:
Type type = typeof(classname);
我开始阅读和研究,我开始玩这样的代码:
public void GetTypeValues<T>() where T : class , new()
对此有点迷茫和困惑,原谅我。
编辑:
基于答案和一些研究,我对此有了更多的了解:
让我们忘记我试图传递一个方法,说我只想传递一个类
假设具有属性的类看起来像这样
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()应该为空还是包含类对象的泛型参数?
答案 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()约束允许您新建事物。
答案 1 :(得分:0)
以下是你的答案:
GetTypeValues<MemberRequestDTO>()
new()
是Type Parameter - T
的约束。它表示类型参数T
必须具有公共无参数构造函数。在您的情况下,MemberRequestDTO
类必须是一个公共无参数构造函数,如下所示:
public class MemberRequestDTO
{
public MemberRequestDTO() { ... }
}
由于班级名称属于reference type
,您可以将其作为type
传递给parens,例如:SomeMethod(typeof(MemberRequestDTO));
,其中方法的签名为void SomeMethod(Type type) { }
}
如果您将该类作为type parameter
传递给第(1)点,则它不会传递到parens()
class
约束意味着“类型参数必须是引用类型;这也适用于任何类,接口,委托或数组类型。”
和new()
约束意味着“类型参数必须具有公共无参数构造函数。当与其他约束一起使用时,必须最后指定new()约束。”
如果我理解你的观点,那么泛型方法定义就像:
public void GetTypeValues<T>(T typeObject) where T : class
{
// typeObject specific operations
}
动态使用typeObject
,让“执行时编译器”执行类型推断以计算T
。 See the reference here.此外,imho,您在new ()
处不需要T
约束。
之后,您可以将任何类的实例传递给此方法,如下所示:
var memberRequestDTO = new MemberRequestDTO();
GetTypeValues((dynamic) memberRequestDTO);
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();
它捕获一个已知方法并返回一个函数,该函数在被调用时将实例化您的类并在其上调用该方法。这是一种更静态的方法(调用者比前一个示例更了解)并且能够强制执行一个约束,使用的类型必须具有无参数构造函数。
我不知道我是否回答了你的问题,但至少应该给你一些想法。