Whole Tomato Software Forums
Whole Tomato Software Forums
Main Site | Profile | Register | Active Topics | Members | Search | FAQ
User name:
Password:
Save Password
Forgot your password?

 All Forums
 Visual Assist
 Technical Support
 VA 2451: extension methods with generics
 New Topic  Reply to Topic
 Printer Friendly
Author Previous Topic Topic Next Topic  

Uniwares
Tomato Guru

Portugal
2322 Posts

Posted - Jul 25 2022 :  11:52:32 AM  Show Profile  Reply with Quote
I have an extension method with a generic type parameter that doesnt get resolved in the definition bar / nav bar. Every other element in here is resolved correctly, except for the ".InvokeByVersion" method.



sample code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;

namespace VersionedInvoker
{
	public interface ITest { string Method1(); }
	public class test : ITest 
	{
		private readonly string version;

		public test(string version)
		{
			this.version = version;
		}

		public string Method1()
		{
			return this.InvokeByVersion<ITest>(this.version, "test").Method1();
		}
	}

	public class test_v1 : ITest { private string p; public test_v1(string t) { this.p = t; } public string Method1() { return this.p; } }
	public class test_v2 : ITest { private string p; public test_v2(string t) { this.p = t; } public string Method1() { return this.p+"2"; } }

	class Program
	{
		public static void Main()
		{
			var t1 = new test("1");
			var t2 = new test("2");
			Console.WriteLine(t1.Method1());
			Console.WriteLine(t2.Method1());
			Console.ReadKey();
		}
	}
	
	static class InvokeExtensions
	{
		/// <summary>
		/// Creates an objet of a similar type as the calling object, taking the callers name, appending a version number.
		/// It then returns the object as the specified interface. The caller and the similar objects must implement the same interface.
		/// </summary>
		/// <param name="caller">The caller.</param>
		/// <param name="version">The version.</param>
		/// <param name="parameters">The parameters to pass to the ctor of the object</param>
		/// <returns>An object of type T</returns>
		public static T InvokeByVersion<T>(this object caller, string version, params object[] parameters) // where T is an interface
		{
			if (string.IsNullOrEmpty(version))
			{
				throw new ArgumentException($"'{nameof(version)}' cannot be null or empty.", nameof(version));
			}

			Type t = caller.GetType();

			version = $"_v{version}";
			string baseClass = t.AssemblyQualifiedName;
			string[] bc = baseClass.Split(',');
			bc[0] += version;

			string versionedClassName = string.Join(",", bc);

			Type t1 = Type.GetType(versionedClassName, false, true);

			if (t1 != null)													
			{
				try
				{
					if((parameters != null) && (parameters.Length > 0))
					{
						// call the ctor with the given parameters
						return (T)Activator.CreateInstance(t1, parameters);
					}
					else
					{
						// call the default ctor with no parameters
						return (T)Activator.CreateInstance(t1);
					}
				}
				catch (System.Exception ex)
				{
					throw new NotSupportedException(t1.Name);
				}
			}

			// method not found, either by its name or by its parameters
			throw new NotImplementedException(t1.Name);
		}
	}
}

feline
Whole Tomato Software

United Kingdom
19063 Posts

Posted - Jul 26 2022 :  10:17:27 AM  Show Profile  Reply with Quote
Thank you for the very clear example. There is currently a known bug with C# generics and carrying the generic type through to the return type, so VA is not understanding the return type, so it doesn't know what methods can be called on the return type:

case=142800

zen is the art of being at one with the two'ness
Go to Top of Page
  Previous Topic Topic Next Topic  
 New Topic  Reply to Topic
 Printer Friendly
Jump To:
© 2023 Whole Tomato Software, LLC Go To Top Of Page
Snitz Forums 2000