lundi 31 janvier 2022

golang how to access promoted type

I have a 'common' structure promoted within two specific structures. For example:

type common struct {
    name string
}

type apple struct {
    common
}

type orange struct {
    common
}

Details specific to apple and orange are omitted.

I have a type-specific map of each, e.g., map[string]*apple and map[string]*orange.

I am trying to make a single function that can extract the common pointers. From what I've tried so far, reflection appears required.

My function is:

func getFruitArray(theMap interface{}) []*common {
    m := reflect.ValueOf(theMap)
    cf := make([]*common, 0, m.Len())
    for _, mk := range m.MapKeys() {
        v := m.MapIndex(mk)
        cf = append(cf, v.Interface().(*common))
    }

    return cf
}

This function fails at cf = append(cf, v.Interface().(*common)) with:

panic: interface conversion: interface {} is *main.apple, not *main.common

Is there a way to access the promoted struct common without specifically referencing apple or orange in this function?

playground example





Setting member variables by name in Spock

I am writing a Spock integration test for a function that takes a DTO, that has a lot of member variables. The functionality to test is that one user role is allowed to change some member variables, but if that user tries to change one of the other fields, it should fail.

I don't want to manually write a test for every single field, so I figured, I could be using a where: table like so:

where:
fieldname | value | isAccepted
"fieldA"  | "val" | true
"fieldB"  | "val" | false
...

For that, I'd have to be able to set the fields by the name in a string. In Java I'd have to use reflection for that. In Python I could just use setattr(object, fieldname, value) for that.

Since I writing the test in Groovy, is there something idiomatic for that?





Check if Annotation is inherited

I have an annotation and three classes like this:

@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}

@MyAnnotation
public class MySuperClass {}

public class MySubClassA extends MySuperClass {}

@MyAnnotation
public class MySubClassB extends MySuperClass {}

Is there any way I can determine if a present annotation is inherited or declared directly at the class?

Something like a method public boolean isInherited(Class<?> clazz, MyAnnotation annotation) that should only be called if the annotation is present.

Exptected output:

isInherited(MySuperClass.class, MySuperClass.class.getAnnotation(MyAnnotation.class)) --> false
isInherited(MySubClassA.class, MySubClassA.class.getAnnotation(MyAnnotation.class)) --> true
isInherited(MySubClassB.class, MySubClassB.class.getAnnotation(MyAnnotation.class)) --> false




samedi 29 janvier 2022

Invalid class name from reflection .NET 6

I'm trying to get all classes from the namespace:

var commands = Assembly.GetExecutingAssembly().GetTypes()
            .Where(t => String.Equals(t.Namespace, nameSpace, StringComparison.Ordinal))
            .ToList();

I have only one class in this namespace:

enter image description here

But, in commands variable I have 2 classes:
enter image description here

I don't understand why it breaks. I also solved this trouble by adding
!t.FullName!.Contains("<>") in where statement of commands, but I don't think that it's perfect solution.
Can somebody explain me why reflection breaks?





How to call generic Method from generic Interface c#?

Error Message:System.ArgumentException: 'Object of type '<>f__AnonymousType2`1[System.String]' cannot be converted to type 'ConsoleApp2.IRequestSimple'

There are my types Request/Response

    public interface IRequestSimple
    {
        public string Field { get; set; }
    }

    public interface IResponseSimple
    {
        public string Answer { get; set; }
    }

    public class MyConsumer : IConsumer<IRequestSimple>
    {
        public async Task Consume(ConsumeContext<IRequestSimple> context)
        {
            Console.WriteLine(context.Message.Field);
            await context.RespondAsync<IResponseSimple>(new { Answer = "Good job" });
        }
    }

I'm trying to call GetResponse but using reflection

var client = mediator.CreateRequestClient<IRequestSimple>();
var response = client.GetResponse<IResponseSimple>(new { });

There is my issue, I need to specify type to calling GetResponse

var requestType = typeof(IRequestSimple);
var responseType = typeof(IResponseSimple);
            
Type type = mediator.GetType();
var methodInfo = typeof(IClientFactory).GetMethods().Where(s => s.Name == "CreateRequestClient" && s.IsGenericMethod).First();
var genericMethod = methodInfo.MakeGenericMethod(requestType);
dynamic requestClient = genericMethod.Invoke(mediator, new object[] { Missing.Value });

Type type1 = requestClient.GetType();
var methodInfo1 = type1 .GetMethods().Where(s => s.Name == "GetResponse").First();
var genericMethod1 = methodInfo1.MakeGenericMethod(responseType);
//Here is my requestClient should be with specified type
var task = (Task)genericMethod1.Invoke(requestClient, new object[] { new { Field = "1" }, Missing.Value, Missing.Value });
await task.ConfigureAwait(false);





vendredi 28 janvier 2022

How to find installed Excel language in C#

Currently I am using the below code to get the excel language

        string strExcelLang = string.Empty;            
        Microsoft.Office.Interop.Excel.Application tExcel = new Microsoft.Office.Interop.Excel.Application(); 
        CultureInfo cExcelCulture = new CultureInfo(tExcel.LanguageSettings.get_LanguageID(Microsoft.Office.Core.MsoAppLanguageID.msoLanguageIDInstall));
            strExcelLang = cExcelCulture.ToString();
        if (strExcelLang.ToUpper().Equals("EN-US") || strExcelLang.ToUpper().Equals("JA-JP"))
        {
            // do something;
        }

However sometimes in client machine we are getting the following error,

System.Runtime.InteropServices.COMException
  HResult=0x80080005
  Message=Retrieving the COM class factory for component with CLSID {00024500-0000-0000-C000-000000000046} failed due to the following error: 80080005 Server execution failed (Exception from HRESULT: 0x80080005 (CO_E_SERVER_EXEC_FAILURE)).
  Source=mscorlib
  StackTrace:
   at System.Runtime.Remoting.RemotingServices.AllocateUninitializedObject(RuntimeType objectType)
   at System.Runtime.Remoting.Activation.ActivationServices.CreateInstance(RuntimeType serverType)
   at System.Runtime.Remoting.Activation.ActivationServices.IsCurrentContextOK(RuntimeType serverType, Object[] props, Boolean bNewObj)
   at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
   at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
   at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
   at System.Activator.CreateInstance(Type type, Boolean nonPublic)
   at System.Activator.CreateInstance(Type type)

Using the excel interop is causing this error. But it won't occur in all machines. Since it is occurring in certain machines, I would like to change the approach to get the installed excel language.

What are the other ways we can achieve this?





jeudi 27 janvier 2022

Initialize Class with Generic Types in Another AppDomain

I am trying to setup a tool I can use to load non-version-specific assemblies from a config/database/etc. at runtime, execute code as needed, and then unload them to eliminate overhead. (My situation has many possible alternate code flows, and I'd like to not force a recompile of the entire app to onboard or edit a single flow)

I've setup a library to run AppDomain.CreateInstanceFromAndUnwrap to initialize classes in separate AppDomains, but as far as I can tell, this doesn't support generic type arguments on the class.

How can I initialize classes with type arguments in a different AppDomain than the executing code from a type name and assembly path? If that's not possible, is there any way to load assemblies in a different AppDomain than the executing code such that it handles dependencies automatically the same way that AppDomain.CreateInstanceFromAndUnwrap does (assuming I could then find a way to call Type.MakeGenericType that executes in the temporary AppDomain from the original AppDomain)?