4

I want to pass in dynamically a class name and a method name to a method and keep this dynamic, I'm understanding that I should use generics and possible constraints.

Example, I have a class

MemberRequestDTO    (contains several properties)

I also that a Method called

RecordsToRetrieve

Using some reflection I was wanting to dynamically get the values of the properties, which I figured out how to do that, but then I realized that is is too hard code and tightly coupled of which I figured time to refactor and create a method with a signature that uses generics with constraints. having trouble with understand the use of and the constraints etc..

So I want to pass in a class name and be able to use it in the method, with reflection I plan to use it like:

Type type = typeof(classname);

I started reading and researching and I start playing with code like this:

public void GetTypeValues<T>() where T : class , new()
  1. How do I pass in the class name of MemberRequestDTO?
  2. What does the Generic new for me?
  3. How do I pass a class name into the parens ()?
  4. If I use does it also get pass into parens?
  5. How can I pass in class and method?
  6. Reading the above "Where T has the constraints (enforced) to be of type "class AND new() ?

A little lost and confused on this, forgive me.

EDIT:

Based on the answers and some research, I'm understanding this a bit more:

Lets forget about me trying to pass in a method, say I just want to pass in a class

Say the class with properties looks like this

 public class MemberRequestDTO
 {

    public DateTime DateRequested { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }
  }

Then I will New this up

var memberRequestDTO = new MemberRequestDTO();

Then I want to pass this to class into a method that is generic

How do I go about passing an instance of a object into a generic method? What about the signature , example public void GetTypeValues() where T : class , new()
Would I want to have the contraints of class and new() ?

For the above, is T the instance of the class? Thus the purpose is that I can be

Saying

GetTypeValues(memberRequestDTO)      

( this is my actual question , pass into whatever class I instantiated and that let the method "handle" dealing with that class with looping through the properties and getting me the name values of the properties dynamically and yes it probably will not remain a void method )

Should passing in memberRequestDTO be with quotes or without? I want to be able to pass in any instance of a class to the member to then manipulate it more. () should T be there ? should the parens () be empty or contain an generic parameter for the class object ?

Wasif Hossain
  • 3,900
  • 1
  • 18
  • 20

3 Answers3

1

Here are your answers:

  1. GetTypeValues<MemberRequestDTO>()
  2. new() is a constraint for the Type Parameter - T. It says that the type argument T must have a public parameterless constructor. In your case, MemberRequestDTO class must a public parameterless constructor like below:

    public class MemberRequestDTO
    {
        public MemberRequestDTO() { ... }
    }
    
  3. As a class name is of reference type, you can pass it as a type into the parens like: SomeMethod(typeof(MemberRequestDTO)); where the signature of the method be void SomeMethod(Type type) { }

  4. If you pass the class as a type parameter as in point (1), it does not get passed into the parens()

  5. class constraint implies that "The type argument must be a reference type; this applies also to any class, interface, delegate, or array type." and new() constraint implies that "The type argument must have a public parameterless constructor. When used together with other constraints, the new() constraint must be specified last."


EDIT:

If I catch your point, then the generic method definition would be something like:

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

That uses typeObject dynamically, getting the "execution-time compiler" to perform type inference to work out T. See the reference here. Moreover, imho, you don't need the new () constraint on T here.

After that, you can pass an instance of any class to this method like below:

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

EDIT 2:

USAGE: Get Type Values dynamically using Reflection

This method returns the property values wrapping into 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;
}
Community
  • 1
  • 1
Wasif Hossain
  • 3,900
  • 1
  • 18
  • 20
  • I added in more information to my question. Hopefully it makes more sense. –  Feb 24 '14 at 05:02
  • I have updated my answer above. Please have a look in the `EDIT` section. and +1 for this good question ! – Wasif Hossain Feb 24 '14 at 05:53
  • How do I use typeObject, example Type type = typeof(typeObject) this cannot be resolved ... i'm using this signature public void GetTypeValues(T typeObject) where T : class –  Feb 24 '14 at 16:38
  • I have updated my answer. Please look into `EDIT 2`. If you have any further query, feel free to ask. Thanks! – Wasif Hossain Feb 25 '14 at 03:05
  • At a loss for why you are casting to dynamic ((dynamic) memberRequestDTO. Since you specify the generic as and then use T in the signature, the compiler is smart enough to figure out T is whatever type you passed in. Even if you did not use T as a parameter you could say GetTypeValues, but you should never have to cast it to a dynamic. – LCarter Feb 25 '14 at 20:30
0

How do I pass in the class name of MemberRequestDTO ?

You already have one. In a generic method "Type parameter" in this case T will be the name of type you're interested in.

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

What does the Generic new for me?

It is a contraint which will prevent you to pass any type without public parameterless constructor. In other words it will allow you to new up type passed in as "Type parameter"

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

How do I pass a class name into the parens () ?

If I use does it also get pass into parens?

Not sure what is that parens() Need more info to answer this.

How can I pass in class and method?

If I understand correctly "Type parameter" T is the runtime type which you use. So you get a Type there. Am not sure about what you mean by class? Class cannot be passed only instances can be passed.

For methods there are number of ways. You can pass MethodInfo or method name or A delegate, or a MethodCallExpression etc.

Reading the above "Where T has the constraints (enforced) to be of type "class AND new() ?

Yes. class constraint prevents you from passing value types, new() constraint allows you to new up things.

Read more about generics here and here

Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
  • Does "T" represent the MemberRequestDTO that I new up an instance and pass in? What I realize that I don't want to do is hard code , thus Type type = typeof(MemberRequestDTO); is not good , i want to use reflection to end up doing typeof(T) -- which T is supposed to be the instance of MemberRequestDTO , then , i further do not want to be using sbBuilder.Append(value + " : " + getFalpaRequest.FirstName).AppendLine(); as I want a generic to determine the property name value. –  Feb 24 '14 at 04:16
0

I'm a little confused about what you want to do but I'll give it a shot. I can see two possible interpretations and they differ on what the caller is starting with and what you're trying to achieve.

Interpretation #1: The caller starts out knowing the name of the class and the name of the method it wants to invoke later, using an object it has in hand. This can be achieved as follows:

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);

This is fine if you need to work with type names and method names dynamically, e.g. from user input. Note that this approach requires the use of object throughout, and will only work with a method that takes no parameters. Also note that in this way the type cannot be guaranteed to have a no-arg constructor, so the caller must provide the object himself.

Interpretation #2: The caller starts out knowing the actual class and the actual method it wants to invoke later, using an object that can be constructed later. This can be achieved as follows:

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();

This captures a known method and returns a function which, when invoked, will instantiate your class and call the method on it. This is a more static approach (the caller knows more than in the previous example) and is able to enforce a constraint that the type being worked with must have a no-arg constructor.

I don't know if I've answered your question but this should at least give you some ideas.

CSJ
  • 3,641
  • 2
  • 19
  • 29