通用厂与类型参数 [英] Generic Factory with type parameter

查看:114
本文介绍了通用厂与类型参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下的情况。



我厂类需要创建基于输入字符串参数传递给CreateStrategy功能相应的策略对象。



Strategy1,Strategy2等都是从一个共同的StrategyBase类派生的。然而,每个策略都有不同的验证机制,这是该类型参数的工厂类。然而,StrategyValidators不是任何普通型的,并有不同的接口。



因此,在下面的代码,我无法指定对StrategyValidator类型的任何共同约束。



我是新的C#,因此不知道是否存在任何机制来克服这个设计问题。请建议

 公共类厂
{
//根据类型创建相应的具体的实现类
公共静态StrategyBase CreateStrategy< StrategyValidator>(字符串型)
{
StrategyBase EnumImp = NULL;

//基于WMI执行
如果(类型==类型1)
{
S = Strategy1< StrategyValidator> .Instance;
}
,否则如果(TYPE =2型)
{
S = Strategy2< StrategyValidator> .Instance;
}
返回小号;
}

私人StrategyBase秒;
}

下面是使用目的

 厂F =新厂(); 

f.CreateStrategy< WMIValidator>(WMI);
f.CreateStrategy&所述; ABCDValidator>(ABCD);



其中, WMIValidator ABCDValidator 是无关的类型,但 CreateStrategy 函数创建实际的类层次结构中的例如与有一个共同的基础 StrategyBase



下面是一个示例代码来说明这个问题。



 命名空间TestCSharp 
{
公共接口IStrategy
{
};

公共接口S1:IStrategy
{
无效F1();
无效F2();
};

公共类S1Concrete:S1
{
公共无效F1(){}
公共无效F2(){}
}

酒店的公共接口S2:IStrategy
{
无效F3();
无效F4();
};

公共类S2Concrete:S2
{
公共无效F3(){}
公共无效F4(){}
};

公共接口ProductBase
{
};

类产品1< T> :ProductBase其中T:S1
{
};

类产品2< T> :ProductBase其中T:S2
{
};

公共类厂
{
公共ProductBase创建< T>(字符串型)
{
如果(类型==P1)
返回新产品1< T>();
,否则如果(类型==P2)
返回新产品2< T>();
}
};

类节目
{
静态无效的主要(字串[] args)
{
厂F =新厂();
ProductBase S = f.Create&所述; S1Concrete>(类型1);
}
}
}



我得到的错误是




类型'T'不能用作泛型类型
或方法TestCSharp.Product1类型参数'T' 。有一个从'T'到'TestCSharp.S1没有装箱转换或
类型参数转换。



解决方案

我认为,在这种情况下,答案是,它的取决于你想要什么产品策略。你似乎想要做的是两个分支分裂你的逻辑。然后你使用泛型要夫妇一遍,但你可以看到,它不会工作。



考虑这样一种情形,类似于你上面 - 但是,在每个班级实施 IStrategy 有一个而不是两个方法,这确实副作用(比如打印一个字符串)。您可以使用泛型时允许类型的范围内有一些共同点。在我刚才提到的情况下,都有一个返回void的方法,不接受参数;因此,我们可以将方法添加到 IStrategy ,例如:

 公开接口IStrategy 
{
无效ExecuteLogic();
};

公共类S1:IStrategy
{
公共无效ExecuteLogic()
{
OneMethod();
}

无效OneMethod()
{
Console.WriteLine(你好);
}
};

公共类S2:IStrategy
{
公共无效ExecuteLogic()
{
TotallyDifferentMethod();
}

无效TotallyDifferentMethod()
{
Console.WriteLine(世界);
}
};

现在,你也说 Strategy1 Strategy2 有不同的验证机制。然而,在我看来,你在相同的方法和上下文(因此相同的参数和变量)使用它们,所以必须有东西,使他们相似。尽管如此,已经定义 IStrategy 在我们要求的方式,我们可以只使用作为创建℃的约束; T> 。因此,工厂变为:

 公共类厂
{
公共ProductBase创建< T>(string类型),其中T:IStrategy
{
如果(类型==P1)
返回新产品1< T>();
,否则如果(类型==P2)
返回新产品2< T>();
返回NULL;
}
};



但还有一种情况。如果你不想让产品1 S2 被称为泛型类型,或产品2 S1 作为其通用的,那么为什么首先使用泛型?你可以很容易的夫妇与他们相关的战略产品,并简化代码显着。



在情况下,我错过了什么(或者是整个的问题),请留下评论,我' ,会尽力去适应我的答案



修改:既然现在你已经重新定义你的榜样,并使用 S1 S2 的接口,我能明白你的意思。一种方法将定义多个泛型类型和约束 Factory.Create 。例如:

 公共ProductBase创建< T1,T2>(string类型),其中T1:S1其中T2:S2 

这是不可能的,否则,你正确地指出,因为有没有共同的祖先 S1 S2 可以通过你的产品类被接受。


I have the following situation.

My Factory class needs to create appropriate Strategy objects based on the input string argument to the CreateStrategy function.

Strategy1, Strategy2 etc are all derived from a common StrategyBase class. However each strategy has a different Validation mechanism which is the type parameter to the Factory class. However, the StrategyValidators are not of any common type and have different interfaces.

Therefore, in the below code, I am unable to specify any common constraint on the StrategyValidator type.

I am new to C# and hence not sure if there exists any mechanism to get over this design issue. Please suggest

public class Factory
{
    //Create the appropriate Concrete Implementation class based on the type
    public static StrategyBase CreateStrategy<StrategyValidator>(String Type)
    {
        StrategyBase EnumImp = null;

        // WMI based implementation
        if (Type == "Type1")
        {
            s = Strategy1<StrategyValidator>.Instance;
        }
        else if (Type = "Type2")
        {
            s = Strategy2<StrategyValidator>.Instance;
        }
        return s;
    }

    private StrategyBase s;
}

Here's the intended usage

Factory f = new Factory(); 

f.CreateStrategy<WMIValidator>("WMI");
f.CreateStrategy<ABCDValidator>("ABCD");

where WMIValidator and ABCDValidator are unrelated types, but the actual classes created by CreateStrategy function are related in a hierarchy e.g. having a common base StrategyBase

Here is a sample code to illustrate the issue

namespace TestCSharp
{
    public interface IStrategy
    {
    };

    public interface S1 : IStrategy
    {
        void f1();
        void f2();
    };

    public class S1Concrete : S1
    {
        public void f1() { }
        public void f2() { }
    }

    public interface S2 : IStrategy
    {
        void f3();
        void f4();
    };

    public class S2Concrete : S2
    {
        public void f3() { }
        public void f4() { }
    };

    public interface ProductBase
    {
    };

    class Product1<T> : ProductBase where T : S1
    {
    };

    class Product2<T> : ProductBase where T : S2
    {
    };

    public class Factory
    {
        public ProductBase Create<T>(String Type)
        {
            if (Type == "P1")
                return new Product1<T>();
            else if (Type == "P2")
                return new Product2<T>();
        }
    };

    class Program
    {
        static void Main(string[] args)
        {
            Factory f = new Factory();
            ProductBase s = f.Create<S1Concrete>("Type1");
        }
    }
}

The error I get is

The type 'T' cannot be used as type parameter 'T' in the generic type or method 'TestCSharp.Product1'. There is no boxing conversion or type parameter conversion from 'T' to 'TestCSharp.S1'.

解决方案

I think that the answer in this case is, it depends on what you want Product and Strategy to do. What you seem to be trying to do is splitting your logic in two branches. Then you want to couple it again by using generics, but as you can notice, it won't work.

Consider a scenario, similar to yours above -- But where each class implementing IStrategy has one instead of two methods which does side effect (i.e. print a string). You use generics when the range of types allowed have something in common. In the case I just mentioned, both have a method returning void and accepting no parameters; so we can add a method to IStrategy, for instance:

public interface IStrategy
{
    void ExecuteLogic();
};

public class S1 : IStrategy
{
    public void ExecuteLogic()
    {
        OneMethod();
    }

    void OneMethod()
    {
        Console.WriteLine("Hello");
    }
};

public class S2 : IStrategy
{
    public void ExecuteLogic()
    {
        TotallyDifferentMethod();
    }

    void TotallyDifferentMethod()
    {
        Console.WriteLine("World");
    }
};

Now, you also said that Strategy1 and Strategy2 have a different validation mechanism. However, it seems to me that you use them in the same method and context (and thus the same parameters and variables), so there must be something that makes them similar. Still, having defined IStrategy in the way we require, we can just use that as a constraint for Create<T>. So, Factory becomes:

public class Factory
{
    public ProductBase Create<T>(String Type) where T : IStrategy
    {
        if (Type == "P1")
            return new Product1<T>();
        else if (Type == "P2")
            return new Product2<T>();
        return null;
    }
};

But there's still one case. If you don't want Product1 to be called with S2 as a generic type, or Product2 to have S1 as its generic, then why using generics in the first place? You could easily couple the products with their relative strategies and also simplify the code remarkably.

In case I missed something (or the entire question) please leave a comment and I'll try to adapt my answer.

EDIT: since now you've redefined your example and used S1 and S2 as interfaces, I can see what you mean. A way would be defining multiple generic types and constraints for Factory.Create. Example:

public ProductBase Create<T1, T2>(String Type) where T1 : S1 where T2 : S2

It would be impossible otherwise, as you properly stated, because there's no common ancestor of S1 and S2 which can be accepted by your Product classes.

这篇关于通用厂与类型参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆