3

我有一个为我创建和设置对象的库,然后我可以使用这些对象来做事。

假设我得到了“A”类的对象“a”

所以我想覆盖该特定对象中的一个方法,我不想更改其类的代码,因为这需要更改库。

在 Ruby 中,我可以使用单例类来做到这一点,例如:

class FirstClass
    def test
        p "test"
    end
end

o = FirstClass.new

class << o
    def test
        p "overridden"
    end
    def extraMethod
        p "ok"
    end
end

o.test # prints "overridden"
o.extraMethod

现在我如何在 C# 中做同样的事情?

更新

我最终没有使用我提交的答案,因为它太丑了,它需要将基类中的所有私有字段更改为保护或公共以使它们存在于派生类中,因此我可以将值从基类复制到派生类。

我最终使用的方法是将派生自基类的 Type 传递给库并更改库,以便它使用以下方法创建实例:

(A)Activator.CreateInstance(mytype, arguments);
4

3 回答 3

4

C# 不(直接)支持类型的运行时扩展,除了通过dynamic机制。

最接近的选择可能是使用ExpandoObjectwith dynamic

dynamic o = new ExpandoObject();
o.a = 10;

o.ExtraMethod = new Action( () => Console.WriteLine("ok") );

// Invoke
o.ExtraMethod();

话虽如此,这并不是使用 C# 的典型方式。

于 2013-05-16T16:34:52.833 回答
1

在 C# 中使用Delegates可以在运行时“覆盖方法”(注意引号)

public class SomeClass
{
    public SomeClass()
    {
        //set the default
        OverridableMethod = () => MessageBox.Show("Default!");
    }

    public void StandardMethod()
    {
        //Call it.
        OverridableMethod();
    }

    public Action OverridableMethod {get;set;}
}

用法:

var some1 = new SomeClass();
some1.StandardMethod(); //Shows "Default!"  
some1.OverridableMethod(); //Shows "Default!"

var some2 = new SomeClass {OverridableMethod = () => MessageBox.Show("Override!!")};
some2.StandardMethod(); //Shows "Override!"  
some2.OverridableMethod(); //Shows "Override!"
于 2013-05-16T16:52:13.190 回答
0

实际上有一种丑陋的方法可以做到这一点。

我正在考虑使用继承和向下转换,但向下转换是无效的。但是,您可以使用反射来实现相同的结果。

static void Main()
        {
            A a = new A();
            a.FieldA = 999; // change the object
            a.test(); // "This is A and FieldA is 999"

            //B b = (B)a; // => Error: Invalid you cannot downcast !

            // using reflection we turn "a" into an instance of B that is a copy of the old "a"
            a = new B(a);
            a.test(); // This will call the method in B: "Calling the new method"  "This is B and FieldA is 999 and FieldB is 10"

            // a.newMethod(); => Error cannot access this method because "a" is declared as an instance of A (even though it's actually of B now)

            B b = (B)a; // Now downcasting works fine (because A is an instance of B actually)

            b.newMethod(); // works as expected: "This is B and FieldA is 999 and FieldB is 10"
        }



        class A
        {
            public int FieldA;

            public A()
            {
                FieldA = 100;
            }

            virtual public void test()
            {
                Console.WriteLine("This is A and FieldA is {0}", FieldA);
            }
        }

        class B : A
        {
            int FieldB;
            public B(A a)
            {
                // copy all fields
                foreach (FieldInfo pi in typeof(A).GetFields())
                    GetType().GetField(pi.Name).SetValue
                       (this, pi.GetValue(a));

                // add this field:
                FieldB = 10;
            }

            // We can override methods
            override public void test()
            {
                Console.WriteLine("Calling the new method:");
                newMethod();
            }

            // Add a new method but it will only be visible after casting A to B
            public void newMethod()
            {
                Console.WriteLine("This is B, FieldA is {0} and FieldB is {1}", FieldA, FieldB);
            }
        }

所以我已经覆盖了“a”中的方法并向它添加了新字段。

我意识到这与您在 Ruby 中可以做的不同,但至少我可以覆盖方法并添加可以在我覆盖的方法中使用的方法/字段。

于 2013-05-16T20:17:57.403 回答