根据类型分配委托?

时间:2009-08-07 15:24:19

标签: c# generics refactoring delegates

我有一个简短的问题。这段代码似乎有些不对劲。我想利用泛型和代理,如果适用的话,很可能利用泛型代表。我正在使用一些代码生成的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;
}

5 个答案:

答案 0 :(得分:0)

您可以将委托和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。

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

答案 1 :(得分:0)

好的,如果我正确地关注你,ADisplayEntityBDisplayEntity都是生成的类看起来几乎一样,对吧?并且您正在尝试创建某种通用委托工厂方法(您称之为Display<T>),允许调用者指定他们想要的显示实体的类型,作为您创建的单个接口进行转换实体实施,是吗?我认为ADisplayBDisplay类没有实现常见的Display()方法,这就是您调用ADisplayBDisplay的原因。嗯......那些与班级同名。错字?您列出的内容甚至无法编译。

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

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

也许有更多信息我可以提供更好的答案,但我在这里看不太重要。除了您的方法的名称与它们实例化的类名称相同,以及您调用与该类名称相同的方法。

答案 2 :(得分:0)

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

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

当然,如果您可以使用 ADisplay 并且 BDisplay 也遵循界面,例如 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;
    }

答案 3 :(得分:0)

如果你想推广这些方法,你可以这样做:

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

答案 4 :(得分:0)

我要假设,因为你提到自动生成了修改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语句,只需添加到字典就可以轻松添加更多IDisplays。

这是我的代码,它在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
    }
}