Применение статического метода к типу - PullRequest
4 голосов
/ 17 января 2012

Я хочу, чтобы класс имел принудительный статический метод с именем GetProduct, чтобы клиентский код мог принимать тип и безопасно вызывать этот статический метод после проверки того, что переданный тип реализует интерфейс с именем ICommandThatHasProduct.

Кажется,что это невозможно, так что теперь я ищу помощь в поиске пути, которым я могу достичь этого.Я знаю, что мог бы использовать отражение, чтобы увидеть, содержит ли тип, который мне передают, метод «GetProduct», но я надеюсь, что существует более объектно-ориентированный способ (т. Е. С использованием наследования).

Любая помощь будетоценили!Код ниже псевдо-c #, определенно не будет компилироваться.

public interface ICommandThatHasProduct
{
    object GetProduct(int id);
}

public abstract class Command : ICommandThatHasProduct
{
    // I want to be able to make the GetProduct method static
    // so that calling code can safely call it
    public static object GetProduct(int id)
    {
        // do stuff with id to get the product
    }

    public object Execute()
    {
        CommandWillExecute();
    }

    public abstract object CommandWillExecute();
}

public class Program
{
    public Program(Type type, int productId)
    {
        if(type == ICommandThatHasProduct)
        {
            // Create the args
            var args = object[1]{ productId };

            // Invoke the GetProduct method and pass the args
            var product = type.InvokeMethod("GetProduct", args);

            //do stuff with product
        }

        throw new Execption("Cannot pass in a Command that does not implement ICommandHasProduct");
    }
}

Ответы [ 5 ]

3 голосов
/ 17 января 2012

Я хочу, чтобы класс имел принудительный статический метод с именем GetProduct, чтобы клиентский код мог принимать объект Type и безопасно вызывать этот статический метод после проверки того, что переданный тип реализует интерфейс.

Вы будете звонить с помощью Reflection, поэтому вам придется выполнять принудительное исполнение также с помощью Reflection.Весь смысл Reflection заключается в том, чтобы во время выполнения выполнить работу, которую компилятор не смог проверить ;если вам нужна проверка во время компиляции, то вы используете не тот инструмент.Не используйте инструмент, специально предназначенный для поражения проверки во время компиляции, если это именно то, что вам нужно!

Я надеюсь, что есть более объектно-ориентированный способ (т.е. используя наследование).

Вы делаете это объектно-ориентированным способом.Ориентация на объект заключается в передаче функциональных единиц в форме объектов и отправке им «сообщений» (называемых вызовами методов), которые описывают, какие операции вы хотите над ними выполнить, и те «сообщения», которые анализируются в конце.мода(Обычно поздняя привязка имеет форму виртуальных вызовов, но поздняя привязка по имени тоже подойдет.)

Наследование - это механизм для совместного использования кода между классами и представления семантических «своего рода» отношений;почему вы считаете, что наследование имеет отношение к вашей проблеме?

3 голосов
/ 17 января 2012

Метод не должен быть статичным.Вместо этого используйте метод member и создайте обычное дерево наследования.

Я предполагаю, что вам нужна абстрактная фабрика или простая реализация шаблона фабричного метода в C #.

Помните LSP .Это помогает избежать странных деревьев наследования.

0 голосов
/ 17 января 2012

Я думаю, что ваша настоящая проблема в том, что вы проходите вокруг Type s вместо собственного класса. GetProduct() -метод фактически принадлежит к классу, который представляет тип команды, но, конечно, вы не можете добавить метод к фактическому Type. Поэтому вместо этого создайте свой собственный класс для представления типа команды.

Полагаю, вы используете Type s для построения фактических Command s с помощью отражения. Если это так, вы на самом деле хотите вместо «Фабрика». (Если не имеет смысла создавать фабрику, просто создайте объект CommandType).

Попробуйте что-то вроде этого:

public interface IFactory{
  object Create();
}

public interface IFactoryThatHasProduct: IFactory
{
  object GetProduct(int id);
}

public class MyCommand
{
  //...
}

public class MyCommandFactory:IFactoryThatHasProduct
{
  object Create(){
    return new MyCommand();
  }

  object GetProduct(int id){
    return //TODO
  }
}

public class Program
{
  public Program(IFactory factory, int productId)
  {
    // consider just having the method take IFactoryThatHasProduct instead of IFactory
    if(factory is IFactoryThatHasProduct){
      var factoryThatHasProduct = (IFactoryThatHasProduct) factory;
      var product = factoryThatHasProduct.GetProduct(productId);
    }
    else{
      throw new Exception("Cannot pass in a factory that does not implement IFactoryThatHasProduct");
    }
  }
}

}

0 голосов
/ 17 января 2012

Почему вы должны называть это статически?Вы можете сделать это:

public class Client 
{
    public void DoSomethingWith<T>() where T : ICommandThatHasProduct, new()
    {
        var command = new T();
        var products = command.GetProducts();
    }
}

или просто так:

public class Client 
{
    public void DoSomethingWith(ICommandThatHasProduct command)
    { 
        var products = command.GetProducts();
    }
}

Вы всегда можете передать экземпляр клиенту вместо типа.

0 голосов
/ 17 января 2012

Принимая во внимание комментарии о том, что это правильный путь, я предполагаю, что вы знаете, что делаете. Вот минимальный пример кода:

using System;
using System.Reflection;

namespace EnforceStaticMethod
{
class Program
{
    static void Main()
    {
        var objA = GetProduct(typeof (TypeA), 1);
        var objB = GetProduct(typeof (TypeB), 2);

        Console.WriteLine("objA has type: " + objA.GetType());
        Console.WriteLine("objB has type: " + objB.GetType());
    }

    static object GetProduct(Type type, int id)
    {
        var argTypes = new[] {typeof (int)};
        var method = type.GetMethod("GetProduct", BindingFlags.Static | BindingFlags.Public, null, argTypes, null);
        if (method == null)
        {
            throw new ArgumentException("Type does not have GetProduct method: " + type);
        }

        var args = new object[] {id};
        return method.Invoke(null, args);
    }
}

class TypeA
{
    public static object GetProduct(int id)
    {
        return new TypeA();
    }
}

class TypeB
{
    public static object GetProduct(int id)
    {
        return new TypeB();
    }
}
}
...