Appending string to to produce a new class nam

2019-08-06 03:37发布

问题:

How do I append string to a type name then pass it as another type? Here is an example:

 public T Get<T>(int id)
        {
           return dbAccess.Get<T>(id);
        }

If I call this method like

SomeObject.Get<Class1>(1234);

I would like to change Class1 to be Class1Data by appending the string "Data" to any passed class, so the dbAccess.Get method would take the object as Class1Data as a conversion of Class1.

回答1:

Something like this would work:

public T Get<T>(int id)
    {
        var newTypeName = typeof(T).FullName + "Data";
        var newType = Type.GetType(newTypeName);
        var argTypes = new [] { newType };
        var method = GetType().GetMethod("Get");
        var typedMethod = method.MakeGenericMethod(argTypes);
        return (T) typedMethod.Invoke(this, new object[] { id });
    }

In case your XxxData object don't inherit from Xxx, you may want to do some automapping before returning the result.

Then you would have to replace the last line to:

        var dataResult = typedMethod.Invoke(this, new object[] { id });
        var result = new T(); // You will have to add a new() constraint on generic parameter
        // Map your dataResult object's values onto the result object's values
        return result;


回答2:

This is not possible because all type parameters must be known at compile time. As long as both methods are generic there's nothing you can do about it.

Usually this kind of translation is performed by switching to reflection and runtime processing; for example, instead of the method's signature being DbAccess.Get<T>(int) it would have to be DbAccess.Get(Type, int).



回答3:

The generic parameter T is a compile time parameter. In other words the compiler pre-processes your code at compile time and the types become fixed at this point.

So, you cannot at runtime change the type that is used for T.

One approach, if you have a constrained set of types, would be to set up the calls to each of them and then switch between them based on the string, e.g.

switch (str)
{
    case "":
        SomeObject.Get<Class1>(1234);
        break;

    case "Data":
        SomeObject.Get<Class1Data>(1234);
        break;
}

Or you could ditch generics completely and look at using reflection instead.