I had a similar use case and this is what worked for me. There might be something you can use. What you would do is make a extension for ITypedValueProvider
and infer the generic type of the caller from this
inside the extension method.
The interface doesn't need to be generic:
public interface ITypedValueProvider
{
TValue GetValue<TValue>();
}
You say you want a generic class of a different T. Here you go:
class TargetValueBase<TClass> : TargetValueBase, ITypedValueProvider { }
Make an instance of it:
var consumer = new TargetValueConsumer<AppDomain>();
So that you can call (for example):
consumer.LogValueForClass<XElement>()
Where a sample extension method (something you can't call on the class directly) might be something like:
public static class Extensions
{
public static string LogValueForClass<TValue>(this ITypedValueProvider @this)
{
var type = @this.GetType();
var builder = new List<string>();
builder.Add($"INFERRED CLASS: { type.GetGenericTypeDefinition().Name.Split('`')[0]}" );
foreach (var arg in type.GetGenericArguments())
{
builder.Add(arg.Name);
}
// Call a generic method on the provider
var getValueResult = @this.GetValue<TValue>();
builder.Add($"The GetValue method returned: {getValueResult}");
return string.Join(Environment.NewLine, builder);
}
}
The TargetValueBase
doesn't need to be generic, either.
class TargetValueBase
{
public TValue GetValue<TValue>()
{
var tValueName = typeof(TValue).Name;
// Figure out what to return.
switch (tValueName)
{
case nameof(XElement):
Console.WriteLine($"Case 1: {tValueName}");
var instance = new XElement("xelement", new XAttribute("hello", "world"));
return (TValue)(object)instance;
case nameof(UInt16):
Console.WriteLine($"Case 2: {tValueName}");
break;
case nameof(UInt32):
Console.WriteLine($"Case 3: {tValueName}");
break;
case nameof(UInt64):
Console.WriteLine($"Case 4: {tValueName}");
break;
}
return default(TValue);
}
public override string ToString() => GetType().Name;
}
Put it all in a little Unit Test...
[TestMethod]
public void GenericGetterTest()
{
string result;
TargetValueBase nonGeneric = new TargetValueBase();
// Calling Generic GetValue doesn't require an extension
// or even a generic class. But that's not what you asked.
Console.WriteLine($"{Environment.NewLine}Calling Generic Method on Non-Generic Value Provider{Environment.NewLine}");
nonGeneric.GetValue<XElement>();
nonGeneric.GetValue<UInt16>();
nonGeneric.GetValue<UInt32>();
nonGeneric.GetValue<UInt64>();
var retail = new TargetValueRetailer<CrossAppDomainDelegate>();
var consumer = new TargetValueConsumer<AppDomain>();
// We make extensions for methods we CAN'T call on the class. Maybe
// the original class is from an external dll, or the class is
// sealed for inheritance, or change all the references is prohibitive.
// What you asked:
// "Generic extension method with one generic type for class and another for value."
// Here's a made-up one:
Console.WriteLine($"{Environment.NewLine}Calling Extension...{Environment.NewLine}");
result = consumer.LogValueForClass<UInt16>();
Console.WriteLine($"{result}{Environment.NewLine}");
Console.WriteLine($"{Environment.NewLine}Calling Extension...{Environment.NewLine}");
result = retail.LogValueForClass<XElement>();
Console.WriteLine($"{retail.LogValueForClass<XElement>()}{Environment.NewLine}");
}
... and run it!

Fun.