5

3つのオーバーロードされたメソッドを持つクラスがあります。たとえば、次のようなものがあります。

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); }
}

このクラスを他の(親)クラスのプライベートフィールドにしたいのですが、これら3つのメソッドにアクセスできる必要があります。今のところ、私はちょうどしました:

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); }
}

1つの短い方法としてそれを実装する方法はありますか?次のようになります。

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

使ってみましpublic void myMethod(params object[] something)たがうまくいきませんでした。それは可能ですか、それともすべてのメソッドを別のメソッドに「投影」する必要がありますか?

編集:子クラスにはさまざまなメソッドとフィールドがあり、親クラスのみがアクセスできるようにしたいと考えています。だから私は親にそれを引き継がせたくないのです。説明しませんでしたが、子クラスにこれら3つのメソッドしか含まれていないように見えた場合は申し訳ありません。これらは、親クラスのパブリックメソッドとしてアクセスできるようにしたいメソッドです。

4

3 に答える 3

2

やってみませんか

class MyChildClass : MyBaseClass
{
}

同じ効果、より少ないコード、そしてこの方法MyChildClassMyBaseClass


リフレクションを使用してある種の一般的なファサードを実装すると、パフォーマンスが低下し、型安全性の利点が回避され、問題の発見が遅れます。

また、クラス名と一致しない「is a」関係ではなく、「hasa」関係があります。


この単純さとそれに関連する利点をあきらめたい場合は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);
    }
}

最終編集

リフレクションを使用するために必要なコードを調べ、型安全性の喪失に関連するコストを検討します。従来の方法で明示的に「has-a」関係を確立する方がよいと思います。

于 2012-12-12T11:10:15.797 に答える
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 に答える
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 に答える