重写内部方法(反射、发射)

Eld*_*asp 0 c# reflection wpf reflection.emit internals

我想创建以下类:

    public class MultiDataOrTrigger : DataTrigger
    {
        public MultiDataOrTrigger()
        {

        }

        // evaluate the current state of the trigger
        internal override bool GetCurrentState(DependencyObject container, UncommonField<HybridDictionary[]> dataField)
        {
            bool retVal = false;

            for (int i = 0; !retVal && i < TriggerConditions.Length; i++)
            {
                retVal = TriggerConditions[i].ConvertAndMatch(StyleHelper.GetDataTriggerValue(dataField, container, TriggerConditions[i].Binding));
            }

            return retVal;
        }
    }
Run Code Online (Sandbox Code Playgroud)

如何调用内部方法,创建内部类型的实例 - 我或多或少弄清楚了。为此,使用反射对我来说就足够了。

但我仍然无法通过重写另一个程序集中指定的虚拟内部方法来弄清楚自己。

更新

回应评论:

我知道这个问题可以在没有这样的课程的情况下解决 - 我知道还有许多其他解决方案或解决方法。我自己在实践中使用了其中的许多内容。由于我不知道如何解决这个问题,我现在还没有停止任何开发。

Jos*_*lva 5

如果这是您真正想要做的,那么是的,可以使用反射发射覆盖另一个程序集中的内部方法。

\n

如果您阅读CLI 规范 (ECMA-335)(特别是第 II.10.3.3 节“可访问性和覆盖”),您会发现:

\n
\n

[注意:即使派生类无法访问方法,也可以重写该方法。

如果一个方法具有程序集可访问性,那么当该方法被不同程序集中的方法覆盖时,该方法也应具有公共可访问性。类似的规则也适用于 famandassem,其中 famorassem 也被允许在集会之外进行。在这两种情况下, assembly 或 famandassem 可以分别在同一程序集中使用。尾注]

\n
\n

(这里,assemblyfamandassem和分别famorassem对应于 C# internalprotected privateprotected internal。)

\n

但是有一个问题!在同一部分中,您还会发现:

\n
\n

如果指定了严格标志 (\xc2\xa7II.23.1.10),则只能覆盖可访问的虚拟方法。

\n
\n

C# 编译器在所有非公共虚拟方法上设置此标志。因此,即使使用反射发射,也无法从 C# 编译的程序集扩展类并覆盖该程序集中声明的内部方法,除非您能够从该方法中删除严格标志(可能使用二进制编辑器,并且如果程序集是强命名则这将使签名无效)。但是你可以使用反射发射创建两个程序集,在第一个程序集中定义一个具有虚拟内部方法的基类,然后扩展该类并重写第二个程序集中的方法,这可以使用以下代码进行演示:

\n
using System;\nusing System.Reflection;\nusing System.Reflection.Emit;\n\npublic interface IBase {\n    void X();\n}\n\nclass Program {\n    \n    public static void Main() {\n        ILGenerator ilGenerator;\n\n        var assembly1 = AssemblyBuilder.DefineDynamicAssembly(\n            new AssemblyName("EmittedAssembly1"),\n            AssemblyBuilderAccess.Run\n        );\n\n        var module1 = assembly1.DefineDynamicModule("EmittedModule1");\n\n        // Define the base class.\n        var typeBuilderBase = module1.DefineType("Base", TypeAttributes.Public);\n        typeBuilderBase.DefineDefaultConstructor(MethodAttributes.Public);\n        typeBuilderBase.AddInterfaceImplementation(typeof(IBase));\n\n        // This is the internal method that will be overridden.\n        var methodBuilderBaseX = typeBuilderBase.DefineMethod(\n            "X",\n            MethodAttributes.Assembly | MethodAttributes.Virtual | MethodAttributes.NewSlot,\n            typeof(void),\n            Array.Empty<Type>()\n        );\n\n        ilGenerator = methodBuilderBaseX.GetILGenerator();\n        ilGenerator.Emit(OpCodes.Ldstr, "X from Base");\n        ilGenerator.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] {typeof(string)}));\n        ilGenerator.Emit(OpCodes.Ret);\n\n        // Define an explicit interface implementation that will be used to call\n        // Base.X() from the created instance of Derived.\n        var methodBuilderBaseInterfaceX = typeBuilderBase.DefineMethod(\n            "IBase.X",\n            MethodAttributes.Private | MethodAttributes.Virtual,\n            typeof(void),\n            Array.Empty<Type>()\n        );\n\n        ilGenerator = methodBuilderBaseInterfaceX.GetILGenerator();\n        ilGenerator.Emit(OpCodes.Ldarg_0);\n        ilGenerator.Emit(OpCodes.Callvirt, methodBuilderBaseX);\n        ilGenerator.Emit(OpCodes.Ret);\n\n        typeBuilderBase.DefineMethodOverride(methodBuilderBaseInterfaceX, typeof(IBase).GetMethod("X"));\n\n        typeBuilderBase.CreateType();\n\n        // This is the assembly in which the internal method will be overridden.\n        var assembly2 = AssemblyBuilder.DefineDynamicAssembly(\n            new AssemblyName("EmittedAssembly2"),\n            AssemblyBuilderAccess.Run\n        );\n        var module2 = assembly2.DefineDynamicModule("EmittedModule2");\n        \n        var typeBuilderDerived = module2.DefineType("Derived", TypeAttributes.Public);\n        typeBuilderDerived.SetParent(typeBuilderBase);\n        typeBuilderDerived.DefineDefaultConstructor(MethodAttributes.Public);\n\n        // Override the internal method in Base. Note that the accessibility of the overridden\n        // method must be public.\n        var methodBuilderDerivedX = typeBuilderDerived.DefineMethod(\n            "X",\n            MethodAttributes.Public | MethodAttributes.Virtual,\n            typeof(void),\n            Array.Empty<Type>()\n        );\n\n        ilGenerator = methodBuilderDerivedX.GetILGenerator();\n        ilGenerator.Emit(OpCodes.Ldstr, "X from Derived");\n        ilGenerator.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] {typeof(string)}));\n        ilGenerator.Emit(OpCodes.Ret);\n\n        var typeDerived = typeBuilderDerived.CreateType();\n\n        // Create an instance of the emitted Derived type.\n        var instance = (IBase)typeDerived.GetConstructor(Array.Empty<Type>()).Invoke(Array.Empty<object>());\n\n        // Call the overridden method. This outputs "X from Derived"!\n        instance.X();\n    }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

如果将MethodAttributes.CheckAccessOnOverride(这是标志)添加到instrict的定义中,您将收到此错误(与尝试使用 C# 编译类型执行此操作时收到的错误相同):XBase

\n
\n

未处理的异常。System.TypeLoadException:来自程序集“EmissedAssembly2,版本= 0.0.0.0,Culture=neutral,PublicKeyToken = null”的类型“Derived”上的方法“X”正在覆盖该程序集中不可见的方法。

\n
\n