>source

기술: 많은 어셈블리에서 1000 개가 넘는 Winforms에서 사용 가능한 모든 컨트롤을 사용하고 싶습니다. 큰 리팩토링 노력을 원하지 않습니다. (작은 도구, 이유는 내부 용)

이미 무엇을: 모든 어셈블리를 얻었으며 모든 어셈블리에서 나에게 흥미로운 모든 유형을 취했습니다. type.IsSubclassOf(selectedType) .

주요 프로젝트 정보: 많은 클래스에는 기본 생성자가 있지만 일부는 다른 기본 클래스를 참조합니다. 프로젝트 구조는 15 년 이상 개발 된 제품이기 때문에 최적이 아닙니다.

문제: 반사를 통해 모든 컨트롤을 사용하려고했습니다. Activator.CreateInstance(type) 그러나 많은 클래스에 대해 처리 할 수없는 예외 또는 기타 기본 클래스 예외를 처리했습니다. 이 절차에서 내가 직면 한 또 다른 문제는 캐스팅이었습니다. 나는 또한 시도했다 FormatterServices.GetUninitializedObject(type) 그러나 나는 통제가 가능한지 여부를 찾지 못했습니다.

질문: 큰 노력없이 winForm 'Form'컨트롤을 이와 같은 구조로 수집 할 수 있습니까? 이것을 달성하는 다른 방법은 무엇입니까?

코드 예

static List<AssemblyName> _assemblyList=new List<AssemblyName>();
static List<Type> _typeList = new List<Type>();
static List<Control> _controlList = new List<Control>();
private static void getFormTypes()
{
    foreach (AssemblyName assemblyName in _assemblyList)
    {
        Assembly assembly = Assembly.Load(assemblyName);
        foreach (Type type in assembly.GetTypes())
        {
            if (type.IsSubclassOf(typeof(Form)))
            {
                _typeList.Add(type);
            }
        }
    }
}
private static void getAllControlsFromFormTypes()
{
    foreach (Type type in _typeList)
    {
        object instance = default;
        
        if (HasValidConstructor(type))
        {
            instance = Activator.CreateInstance(type);//Here I have unhandled exceptions from base classes during constructor invoking
            GetValidControls((Control)instance);
        }
    }
}
private static void GetValidControls(Control container)
{
    foreach (Control control in container.Controls)
    {
        GetValidControls(control);
        if (!string.IsNullOrEmpty(control.Name) && !string.IsNullOrEmpty(control.Text))
        {
            _controlList.Add(control);
        }
    }
}
public static bool HasValidConstructor(Type t) => t.IsValueType || !t.IsAbstract && t.GetConstructor(Type.EmptyTypes) != null;```


  • 답변 # 1

    양식에 컨트롤을 놓으면 디자이너가 컨트롤에 대한 멤버 필드를 만듭니다. 변경하지 않은 경우 GenerateMember 속성을 사용하여이 동작을 변경하거나 멤버 변수없이 레이블을 만드는 데이터 폼 마법사를 사용하지 않은 경우 폼을 인스턴스화하지 않고도 해당 멤버 필드를 사용하여 모든 컨트롤을 가져올 수 있습니다.

    각 어셈블리에 대해 다음과 같이 인스턴스화하지 않고도 양식 및 컨트롤 목록을 얻을 수 있습니다.

    IEnumerable<Type> GetFormsAndControlsTypes(Assembly assembly)
    {
        var forms = assembly.GetTypes()
            .Where(type => typeof(Form).IsAssignableFrom(type));
        var controls = forms.SelectMany(
            form => form.GetFields(
                BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                .Where(field => typeof(Control).IsAssignableFrom(field.FieldType))
                .Select(field => field.FieldType));
        return forms.Concat(controls).Distinct().ToList();
    }
    
    

    그러나 일반적으로 이러한 작업은 런타임 작업이 아니라 코드 분석처럼 보입니다.

  • 이전 regex - 파이썬에서 마커 사이에 문자열 가져 오기
  • 다음 android - IN 연산자로 Enum 목록을 제공하는 룸 데이터베이스 쿼리 사용