5

我有一个类,它有三个重载方法。比方说,有:

class MyChildClass
{
    public void myMethod(int i)
        { /* do something with i */ }
    public void myMethod(int a, string b)
        { /* get i from a and b and call: */ myMethod(i); }
    public void myMethod(string c, string d)
        { /* get i from c and d and call: */ myMethod(i); }
}

现在我希望这个类成为其他(父)类中的私有字段,但我需要这三种方法可以访问。现在,我刚刚做了:

class MyBaseClass
{
    private MyChildClass myObject = new myChildClass(); // or similar
    public void myMethod(int i) 
        { myObject.myMethod(i);    }
    public void myMethod(int a, string b) 
        { myObject.myMethod(a, b); }
    public void myMethod(string c, string s) 
        { myObject.myMethod(c, d); }
}

有没有办法将它作为一种短方法来实现?看起来像:

public void myMethod(unknownListOfArgumentsOfDifferentTypes args)
    { myObject.myMethod(args); }

我尝试使用public void myMethod(params object[] something)但没有用。有可能,还是我必须将每种方法“投影”到另一种方法中?

编辑:子类有各种方法和字段,我希望仅父类可以访问它们。这就是为什么我不希望父母继承它。我没有解释,对不起,如果它看起来像子类只包含这三个方法。这些是我希望作为父类的公共方法访问的方法。

4

3 回答 3

2

你为什么不做

class MyChildClass : MyBaseClass
{
}

效果一样,代码少,这种方式MyChildClassMyBaseClass


如果您使用反射实现某种通用外观,您只会降低性能,绕过类型安全的好处并延迟问题的发现。

您还将有一个“具有”关系而不是“是”关系,这与您的类名不一致。


如果您想放弃这种简单性及其相关的好处,您可以使用本文中GetMethodBySig接受的扩展。

像这样的东西,

class SemiGenericFacade<T> where T : new()
{
    private readonly t = new T();

    public void CallVoidOnT(string name, params object[] parameters)
    {
        var paramTypes = parameters.Select(p => typeof(p))

        var match = typeof(T).GetMethodBySig(typeof(void), paramTypes)
            .Single(mi => mi.Name == name);

        match.Invoke(this.t, parameters);
    }
}

根据 Piotr Justyna 的评论,实施和使用这种方法会导致猫变成老虎并吃掉她的小猫。


如果你要这样做,添加到链接的扩展是有意义的

public static class Extensions
{
    public static MethodInfo GetMethodByNameThenSig(
        this Type type,
        string name, 
        Type returnType, 
        params Type[] parameterTypes)
    {
        return type.GetMethods().Where((m) =>
        {
            if (m.Name != name)
            {
                return false;
            }

            if (m.ReturnType != returnType)
            {
                return false;
            }

            var parameters = m.GetParameters();
            if ((parameterTypes == null || parameterTypes.Length == 0))
            {
                return parameters.Length == 0;
            }

            if (parameters.Length != parameterTypes.Length)
            {
                return false;
            }

            for (int i = 0; i < parameterTypes.Length; i++)
            {
                if (parameters[i].ParameterType != parameterTypes[i])
                {
                    return false;
                }
            }

            return true;
        }).Single();
    }
}

你可以这样使用,

class GenericFacade<T> where T : new()
{
    private readonly t = new T();

    public void CallOnInternal(string name, params object[] parameters)
    {
        var paramTypes = parameters.Select(p => typeof(p))

        var match = typeof(T).GetMethodByNameThenSig(
            name,
            typeof(void),
            paramTypes);

        match.Invoke(this.t, parameters);
    }

    public TResult CallOnInternal<TResult>(string name, params object[] parameters)
    {
        var paramTypes = parameters.Select(p => typeof(p))

        var match = typeof(T).GetMethodByNameThenSig(
            name,
            typeof(TResult),
            paramTypes);

        return (TResult)match.Invoke(this.t, parameters);
    }
}

最终编辑

查看使用反射所涉及的代码,并考虑与类型安全损失相关的成本。我建议最好以传统方式明确建立“有”关系。

于 2012-12-12T11:10:15.797 回答
1

显而易见的答案是继承。

在您的情况下(即使类的名称另有说明),这样做的方法是继承 BaseClass 中的 ChildClass,这样您就可以通过 BaseClass 公开 ChildClass 的方法。

前任:

class MyBaseClass: MyChildClass
{
}

如果这些类不相关,并且您只想在 MyBaseClass 中有一个 MyChildClass 的实例,但只公开一组方法但不将其他方法设为私有,您可以做的是通过只公开必要的接口公开 MyChildClass 实例像这样的字段:

public class BaseClass
{
    public  IChildClass ChildClassInstance = new ChildClass();
}

public class ChildClass : IChildClass
{
    public void myMethod(int i)
    { /* do something with i */ }
    public void myMethod(int a, string b)
    { /* get i from a and b and call: */ myMethod(i); }
    public void myMethod(string c, string d)
    { /* get i from c and d and call: */ myMethod(i); }
}

public interface IChildClass
{
    void myMethod(int i);
    void myMethod(int a, string b);
}

然后您只能访问允许通过基类实例公开的方法:

BaseClass test = new BaseClass();
test.ChildClassInstance.myMethod(1);
test.ChildClassInstance.myMethod(1,"test");
于 2012-12-12T11:21:45.863 回答
1

您可以使用public void myMethod(params object[] something)如下:

public static void Main()
{
    UnknownArgumentsMethod1(1, 2, 3, "foo");
}

public static void UnknownArgumentsMethod1(params object[] list)
{
    UnknownArgumentsMethod2(list);
}

public static void UnknownArgumentsMethod2(params object[] list)
{
    foreach (object o in list)
    {
        if (o.GetType() == typeof(int))
        {
            Console.WriteLine("This is an integer: " + (int)o);
        }
        else if (o.GetType() == typeof(string))
        {
            Console.WriteLine("This is a string: " + (string)o);
        }
    }
}
于 2012-12-12T11:21:01.190 回答