在类型上强制执行静态方法

发布于 2024-12-27 06:38:06 字数 1232 浏览 0 评论 0原文

我希望一个类具有一个名为 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");
    }
}

I want a class to have an enforced static method called GetProduct, so that client code can accept a type and safely call that static method after checking that the passed type implements an interface called ICommandThatHasProduct.

It seems that this is not possible, so now I'm seeking help in finding a way I can achieve this. I know that I could use reflection to see if the type I am passed contains a method called "GetProduct" but I am hoping there is a more object-oriented way (i.e. using inheritance).

Any help will be appreciated! The below code is pseudo-c#, definitely will not compile.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

治碍 2025-01-03 06:38:06

方法不必是静态的。请改用成员方法,并创建通常的继承树。

我猜您正在寻找 抽象工厂 或 C# 中的简单工厂方法模式实现。

请牢记LSP。它有助于避免看起来奇怪的继承树。

Method does not have to be static. Use a member method instead, and create the usual inheritance tree.

I am guessing you're looking for an abstract factory or a simple factory method pattern implementation in C#.

Keep LSP in mind. It helps to avoid strange-looking inheritance trees.

无声静候 2025-01-03 06:38:06

我希望一个类有一个名为 GetProduct 的强制静态方法,以便客户端代码可以接受 Type 对象,并在检查传递的类型是否实现接口后安全地调用该静态方法。

您将通过反射进行调用,因此您也必须通过反射进行执行。反射的全部要点是在运行时执行编译器无法验证的工作;如果您想要的是编译时验证,那么您使用的工具完全错误。如果您确实想要这样做,请不要使用专门设计来击败编译时验证的工具!

我希望有一种更面向对象的方式(即使用继承)。

您正在以面向对象的方式进行操作。面向对象是以对象的形式传递功能单元,并向它们发送“消息”(也称为方法调用),描述您想要对它们执行什么操作,以及稍后分析这些“消息”绑定时尚。 (通常后期绑定采用虚拟调用的形式,但通过名称进行后期绑定也可以。)

继承是一种在类之间共享代码并表示语义“是一种”关系的机制;为什么您认为继承与您的问题相关?

I want a class to have an enforced static method called GetProduct, so that client code can accept a Type object and safely call that static method after checking that the passed type implements an interface.

You're going to be making the call via Reflection, so you're going to have to do the enforcement via Reflection too. The whole point of Reflection is to do work at runtime that the compiler was unable to verify; if what you want is compile-time verification then you're using exactly the wrong tool. Don't use a tool specifically designed to defeat compile-time verification if that is the very thing you want!

I am hoping there is a more object-oriented way (i.e. using inheritance).

You are doing it the object-oriented way. Object-orientation is about passing around units of functionality in the form of objects, and sending them "messages" (aka method calls) that describe what operations you'd like to perform on them, and those "messages" being analyzed in a late-bound fashion. (Usually the late binding is in the form of virtual calls, but late binding by name is fine too.)

Inheritance is a mechanism for sharing code between classes and representing semantic "is a kind of" relationships; why do you feel that inheritance is relevant to your problem?

一抹淡然 2025-01-03 06:38:06

我认为你真正的问题是你传递的是 Type 而不是你自己的类。 GetProduct() 方法实际上属于表示命令类型的类,但当然您不能在实际的 Type 上添加该方法。因此,请创建自己的类来表示命令的类型。

我猜您正在使用 Type 通过反射构造实际的 Command。如果是这样,您实际上需要一个“工厂”。 (如果创建工厂没有意义,只需创建一个“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");
    }
  }
}

}

I think your real problem is that you are passing around Types instead of a class of your own. The GetProduct()-method actually belongs on the class that represents the type of command, but of course you cannot add the method on the actual Type. So instead make your own class to represent the type of command.

I guess you are using the Types to construct the actual Commands via reflection. If so, you actually want a 'Factory' instead. (If it does not make sense to make a factory, just make a 'CommandType' object instead).

Try something like this:

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

}

来世叙缘 2025-01-03 06:38:06

考虑到关于这是否是正确的方法的评论,我假设您知道自己在做什么。这是一个最小的代码示例:

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

Taking on board the comments about whether this is the right way to go, I'll assume you know what you are doing. Here is a minimal code sample:

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();
    }
}
}
想挽留 2025-01-03 06:38:06

为什么需要静态调用它?您可以这样做:

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

您始终可以将实例而不是类型传递给客户端。

Why do you need to call it staticly? You could do this:

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

or just this:

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

You can always pass the instance to the client instead of the type.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文