【问题标题】:Assign a delegate based on a type?根据类型分配委托?
【发布时间】:2010-11-17 17:45:53
【问题描述】:

我有一个简短的问题。这段代码似乎真的有问题。我想利用泛型和委托,如果适用的话,很可能是泛型委托。我正在使用一些代码生成的 api,并且生成的对象非常相似。我看到它们都实现了一个接口,所以我尝试用几种方法创建一个类来处理不同的场景。这是一些示例代码。只是在很多层面上都感觉不对。请告诉我如何使这段代码更好。如果您愿意,请提供一些重构建议。并且一定要把它撕成碎片。我想更好地编码并学会正确地做事。

private delegate IsomeEntity DisplayDelegate(IsomeEntity display);

public IsomeEntity Display<T>()
{
    DisplayDelegate _del = null;
    IsomeEntity display = factory.CreateObject(typeof(T).Name);

    if (display.GetType() == typeof(ADisplayEntity))
        _del = ADisplayEntity;

    if (display.GetType() == typeof(BDisplayEntity))
        _del = BDisplayEntity;

    if (display.GetType() == typeof(CDisplayEntity))
        _del = CDisplayEntity;


    return _del(display);
}

public ADisplayEntity ADisplayEntity(IsomeEntity display)
{
    ADisplayEntity ade = display as ADisplayEntity;

    try
    {
        ADisplay o = new ADisplay();
        ADisplayEntity response = o.ADisplay(ade);
        return response;
    }
    catch (Exception ex)
    {
        Exception newEx;
        if (someExceptionHandler.HandleException(ex, this, out newEx))
            throw newEx;
    }

    return null;
}

public BDisplayEntity BDisplayEntity(IsomeEntity display)
{
    BDisplayEntity dde = display as BDisplayEntity;

    try
    {
        BDisplay o = new BDisplay();
        BDisplayEntity response = o.BDisplay(bde);
        return response;
    }
    catch (Exception ex)
    {
        Exception newEx;
        if (someExceptionHandler.HandleException(ex, this, out newEx))
            throw newEx;
    }

    return null;
}

【问题讨论】:

    标签: c# generics refactoring delegates


    【解决方案1】:

    您可以将委托和 lambda 函数作为通用值传递,如下所示:

    public ISomeEntity Display<T>( Func<T, ISomeEntity> conversion )
    {
        IsomeEntity display = factory.CreateObject(typeof(T).Name);
        return conversion(display);
    }
    

    然后调用它是:

    var myNewEntity = Display( 
        x => ADisplay.GetADisplay(x as ADisplayEntity) );
    

    等等。

    我不完全确定您要做什么 - 所以我的代码可能不太正确,但它应该让您了解如何传递 lambda。

    您甚至可以将它们存储在字典中并进行查找。

    【讨论】:

    • 我认为他希望在 Display 方法中使用该代码,这样他就不必在每次需要 ISomeEntity 时都指定它
    【解决方案2】:

    好的,如果我没听错的话,ADisplayEntityBDisplayEntity 都是生成的类,看起来几乎一样,对吧?而且您正在尝试创建某种通用委托工厂方法(您称为Display&lt;T&gt;),它允许调用者指定他们想要的显示实体的类型,将其转换为您创建的实体实现的单个接口, 是的?我认为ADisplayBDisplay 类没有实现通用的Display() 方法,这就是为什么你要调用ADisplayBDisplay。嗯...这些与班级同名。错字?您列出的内容甚至无法编译。

    我认为需要一个更好的例子。我意识到您正在尝试清理您的代码,但也许一些更改名称的真实代码可能会更好。我想看看ADisplayBDisplayADisplayEntityBDisplayEntity 到底是什么。

    也就是说,如果各种 A/BDisplayA/BDisplayEntity 类真的如此不同,以至于您无法将这些委托方法合并到一个方法中,那么您几乎是在做唯一可以做的事情来实现您的原始目标。

    也许有了更多信息,我可以提供更好的答案,但我认为这里没有太多需要重构的地方。除了您的方法名称与它们实例化的类名称相同以及您对与该类名称相同的方法的调用之外。

    【讨论】:

      【解决方案3】:

      为什么不简单呢?为什么你需要代表..等等

       public static ISomeEntity DisplayEntity(ISomeEntity display)
      {
      
               ISomeEntity result;
                 if (entity is ADisplayEntity)
                  {
                      ADisplay disp = new ADisplay();
                      result = disp.ADisplayFunc();
                  }
                if(entity is BDisplayEntity)
                 {
                      BDisplay disp = new BDisplay();
                      result = disp.BDisplayFunc();
                 }
      
          return result;
      }
      

      当然,如果你可以让你的 ADisplayBDisplay 也遵循一个界面,比如 IDisplay 那么你只需要返回 IDisplay.Display(ISomeEntity)

      接下来,您可以像这样包装您的显示器..

      public interface IDisplay
      {
          public ISomeEntity Display(ISomeEntity entity);
      }
      
      public class AWrappedDisplay: IDisplay
      {
          public ISomeEntity Display(ISomeEntity entity)
          {
              ADisplay disp = new ADisplay();
              return disp.ADisplayFunc(entity);
          }
      
      }
      
      public class BWrappedDisplay : IDisplay
      {
          public ISomeEntity Display(ISomeEntity entity)
          {
              BDisplay disp = new BDisplay();
              return disp.BDisplayFunc(entity);
          }
      
      }
      
      public static IDisplay Factory(Type t)
              {
                 IDisplay disp = null;
                 if (t == typeof(ADisplayEntity))
                     disp = new AWrappedDisplay();
      
                 if (t == typeof(BDisplayEntity))
                     disp = new BWrappedDisplay();
      
                  return disp;
              }
      

      然后你可以像这样调用你的 DisplayEntity

        public static ISomeEntity DisplayEntity(ISomeEntity display)
          {
              IDisplay disp = Factory(display.GetType());
              ISomeEntity newDisplayEntity = disp.Display(display);
      
              return newDisplayEntity;
          }
      

      【讨论】:

        【解决方案4】:

        如果你想概括这些方法,你可以这样做:

        private delegate IsomeEntity DisplayDelegate<T>(IsomeEntity display);
        
            public IsomeEntity DisplayMethod<T>() where T : IsomeEntity
            {
                DisplayDelegate<T> _del = new DisplayDelegate<T>(DoDisplay<T>);
                IsomeEntity entity = factory.CreateObject(typeof(T).Name);
        
                return _del(entity);
            }   
        
            public IsomeEntity DoDisplay<T>(IsomeEntity entity)
            {
                try
                {
                    Display<T> o = new Display<T>();
                    Entity<T> response = o.Display(entity);
                    return response;
                }
                catch (Exception ex)
                {
                    if (someExceptionHandler.HandleException(ex, this, out newEx))
                        throw newEx;
                }
            }
        

        这种情况下,确实不需要委托,直接调用DoDisplay即可。

            public IsomeEntity DisplayMethod<T>() where T : IsomeEntity
            {            
                IsomeEntity entity = factory.CreateObject(typeof(T).Name);
        
                return DoDisplay<T>(entity);
            }   
        
            public IsomeEntity DoDisplay<T>(IsomeEntity entity)
            {
                try
                {
                    Display<T> o = new Display<T>();
                    Entity<T> response = o.Display(entity);
                    return response;
                }
                catch (Exception ex)
                {
                    if (someExceptionHandler.HandleException(ex, this, out newEx))
                        throw newEx;
                }
            }
        

        【讨论】:

        • 我看到你在这里做了什么,但你的例子无法编译,o 到底是什么类型,o 怎么有 o .显示(实体)
        • 我的例子是基于 OP 的,OP 有“ADisplay”和“BDisplay”。我只是将它重命名为“显示”,因为它是通用的。该示例用于语法和设计,它不包括实际编译、构建和运行所需的一切。实施细节留给用户。
        【解决方案5】:

        我将假设,因为您提到修改 ISomeEntity 的东西是自动生成的(否则我建议向 ISomeEntity 添加一个 Display() 方法,然后通过接口直接在实体上调用它。每个实体都会实现自己的 Display()) 版本。

        所以,如果我了解您的代码试图正确执行的操作(不是很清楚),我建议创建一个 IDisplay 接口,让 ADisplay 和 BDisplay 继承自它。该接口将有一个 Display() 方法,该方法接受 ISomeEntity 并返回 ISomeEntity。但是,如果 ADisplay.Display(ISomeEntity) 接收到 BDisplayEntity,则会引发异常。

        然后,我将创建一个 IDictionary,您将其作为字段存储在具有该主要 Display 方法(我将称之为 Displayer)的类中。该字典将存储用于每种类型的 IDisplay(即 typeof(ADisplayEntity) -> new ADisplay())。

        然后您可以将您的主要 Display 方法添加到 Displayer,但现在让它返回一个通用 T,因为 T 是您正在创建和返回的类型。此方法查找它需要的 IDisplay 并在工厂创建的 ISomeEntity 上使用它,并返回其结果。

        使用字典意味着您不会得到一堆糟糕的 if 语句,并且您可以通过添加到字典中轻松添加更多 IDisplay。

        这是我的代码,在 VS2008 中编译。

        public interface ISomeEntity
        {
        
        }
        
        public class EntityFactory
        {
            public ISomeEntity CreateObject(string name)
            {
                //Do factory stuff here
                return null;
            }
        }
        
        public class ADisplayEntity : ISomeEntity
        {
        }
        
        
        
        public class BDisplayEntity : ISomeEntity
        {
        }
        
        public interface IDisplay
        {
            ISomeEntity Display(ISomeEntity entity);
        }
        
        public class ADisplay : IDisplay
        {
            public ISomeEntity Display(ISomeEntity entity)
            {
                ADisplayEntity aEntity = entity as ADisplayEntity;
                if (aEntity == null)
                    throw new ArgumentException("Wrong type");
        
                //Do whatever happens when you convert parameter entity into a
                //"response" ADisplayEntity. I'm just returning a new 
                //ADisplayEntity to make it compile for me
                return new ADisplayEntity();
            }
        }
        
        public class BDisplay : IDisplay
        {
            public ISomeEntity Display(ISomeEntity entity)
            {
                BDisplayEntity bEntity = entity as BDisplayEntity;
                if (bEntity == null)
                    throw new ArgumentException("Wrong type");
        
                //Do whatever happens when you convert parameter entity into a
                //"response" BDisplayEntity. I'm just returning a new 
                //BDisplayEntity to make it compile for me
                return new BDisplayEntity();
            }
        }
        
        
        
        public class Displayer
        {
            private IDictionary<Type, IDisplay> displayers;
            private EntityFactory factory;
        
        
            public Displayer()
            {
                factory = new EntityFactory();
                displayers = new Dictionary<Type, IDisplay>
                                {
                                    { typeof(ADisplayEntity), new ADisplay() },
                                    { typeof(BDisplayEntity), new BDisplay() }
                                };
            }
        
        
            public T Display<T>() where T : class, ISomeEntity
            {
                T entity = factory.CreateObject((typeof(T).Name)) as T; //Type-safe because of the factory
                IDisplay displayer = displayers[typeof(T)];
                return displayer.Display(entity) as T; //Typesafe thanks to each IDisplay returning the correct type
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-03
          • 1970-01-01
          • 2017-02-05
          • 2019-02-23
          • 2011-09-15
          • 1970-01-01
          • 2011-04-09
          • 1970-01-01
          相关资源
          最近更新 更多