使用设计模式在C#中为类添加功能 [英] Use a Design Pattern to add functionality to a class in C#

查看:141
本文介绍了使用设计模式在C#中为类添加功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的挑战:将从XML到序列化和反序列化的能力添加到仅了解如何使用JSON的类。



我是新来的C#,虽然我熟悉设计模式的基本应用程序。



一位同事建议如下:



我的建议是注入一个串行器(写一个IRDCSerizliazer界面,它是一个装饰器/适配器,用于包装它所构造的串行器)。



非常大的开/关原则在这里,这可能是为什么建议使用界面和
模式,而不是添加任何代码到类。


$ b $我刚刚在C#中创建了一个示例Decorator模式,以确保我了解如何做标准装饰器模式
,并感觉到这种情况复杂的方式...(虽然我是很高兴得到纠正)



我想我需要一些抽象Serializer的东西,并允许Seriali zer.serialize()和Serializer.deserialize()
从我现在只知道JSON的工作类中调用。我也认为我可以根据它的构造方式在Serializer中有JSON代码或XML代码。 I.E.我正在从我的同事的提示中假设他正在建立这样的模式...



我可以感觉到这个我的舌头,就像他们说的那样有麻烦的飞跃。 纯装饰图案
似乎太复杂了。帮助将不胜感激。



请不要在办公室要求更多的帮助,显然我不想这样做,在这里请求帮助。



我的工作者类在下面 - 你会看到,目前它只是直接调用JSON序列化和反序列化...显然,必须改变不要太担心它的作用 - 这是一个棘手的反思内容 - 关键是可以使用这种注入接口这个概念在XML中序列化和反序列化XML以及JSON。

 命名空间XXXXXXXXXXXX 
{
public interface IRecordSearchClientAdapter
{
string CallCorrectMethod(ClientServiceTypes component,string方法,字符串请求,Type [] paramTypes);
}

public class RecordSearchClientAdapter:IRecordSearchClientAdapter
{
private IDictionary< ClientServiceTypes,object> componentMappings;

public static IRecordSearchClientAdapter Create(IDictionary< ClientServiceTypes,object> clients)
{
返回新的RecordSearchClientAdapter(clients);
}

private RecordSearchClientAdapter(IDictionary< ClientServiceTypes,object> clients)
{
componentMappings = clients;
}
public string CallCorrectMethod(ClientServiceTypes component,string method,string request,Type [] paramTypes)
{
dynamic parsedrequest = Newtonsoft.Json.JsonConvert.DeserializeObject< dynamic>请求);
//使用另一种方法来决定是JSON还是XML,不用担心注入一个Decorator:Interface?
// dynamic parsedrequest = DeserializeObject(request);
return CallCorrectMethod(component,method,parsedrequest,paramTypes);
}

//在此方法中,检查XML或JSON - 然后转发到适当的方法。
private string DeserializeObject(string request)
{
// stub - fixme!
返回null;
}

私有字符串CallCorrectMethod(ClientServiceTypes组件,字符串方法,JObject请求,Type [] paramTypes)
{
object client = componentMappings [component];

MethodInfo mi = FindExactMethod(client,method,request,paramTypes);

string response = null;

if(paramTypes.Length == 1)//只有一个请求对象
{
var obj = DeserializeGenericObject(request,paramTypes [0]);
var methodResponse = mi.Invoke(client,new object [] {obj});
response = Newtonsoft.Json.JsonConvert.SerializeObject(methodResponse);
}
else //多个参数,需要从请求中获取
{
JEnumerable< JToken> tokens = request.Children();
IEnumerator< JToken> tokenEnumerator = tokens.GetEnumerator();
列表< object> args = new List< object>();
foreach(在paramTypes中键入t)
{
if(!tokenEnumerator.MoveNext())
{
throw new ArgumentException(请求中的参数数不是 t匹配方法中的参数数量);
}

args.Add(DeserializeGenericObject(tokenEnumerator.Current.First,t));
}
var methodResponse = mi.Invoke(client,args.ToArray());
response = Newtonsoft.Json.JsonConvert.SerializeObject(methodResponse);
}

返回响应;
}

private MethodInfo FindExactMethod(对象客户端,字符串方法,JObject请求,Type [] paramTypes)
{
//获取与名称和类型参数
MethodInfo mi = client.GetType()。GetMethod(method,BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance,null,paramTypes,null);
return mi;
}

私有对象DeserializeGenericObject(JToken token,Type objectType)
{
键入myClassType = this.GetType();
MethodInfo methodToCall = myClassType.GetMethod(DeserializeGenericTemplate,BindingFlags.IgnoreCase | BindingFlags.NonPublic | BindingFlags.Instance);
MethodInfo genericMethodToCall = methodToCall.MakeGenericMethod(new Type [] {objectType});
object newObject = genericMethodToCall.Invoke(this,new [] {token});

return newObject;
}

private T DeserializeGenericTemplate< T>(JToken token)
{
T obj = token.ToObject< T>
return obj;
}
}

}

解决方案

不知道为什么你需要在一个类中。你的设计似乎是一种过度的杀戮。我将有一个界面定义常见的行为(序列化和反序列化)和两个实现类,一个用于JSON,另一个用于XML,类似于

  public interface ISerialize< T> 
{
T Deserialize< T>(string input);
string Serialize(T type)
}

public class JsonSerializer< T> :ISerialize< T>
{
T Deserialize< T>(string input){...}
string Serialize(T type){...}
}

public class XmlSerializer< T> :ISerialize< T>
{
T Deserialize< T>(string input){...}
string Serialize(T type){...}
}

这里是如何使用它

  public class Foo< T> 
{
private ISerializer< T> _serialiser;

public Foo< T>(ISerializer< T>串行器)
{
_serialiser =串行器;
}

void DoFoo()
{
string result = serialiser.Serialize(instanceOfA_1);
var instanceOfA_2 = serialiser.Deserialize< ClassA>(result);
}
}

如果您不知道需要哪个序列化程序,使用一个界面,例如通过将其注入到构造函数中。


My challenge: Add the ability to serialize and deserialize from/to XML to a class that only knows how to do this with JSON.

I'm new to C#, although I'm conversant with the "basic" application of Design Patterns.

A colleague suggested the following:

My recommendation is that you inject a serializer (write an IRDCSerizliazer interface that is a decorator/adapter that wraps whichever serializer it is constructed with).

They're very big on the "open/closed" principle here, which is probably why the suggestion was to use an interface and a pattern rather than adding any code to the class.

I just built a sample "Decorator" pattern in C# to make sure I understood how to do the "standard" decorator pattern and it feels way to complex for this situation... (although I'm happy to be corrected)

I think I need something that abstracts "Serializer" and allows "Serializer.serialize() and Serializer.deserialize() to be called from my worker class that currently only knows about JSON. I also think I want to be able to have either the JSON code or the XML code in "Serializer" based on how it is constructed. I.E. I'm assuming from my colleague's tip that he's built patterns like this...

I can feel this "on the tip of my tongue" as they say, but am having trouble making the leap. A "pure" Decorator pattern seems too complex. Help would be appreciated.

Please don't flame about how I should ask for more help at the office - obviously I don't want to do that or I wouldn't be asking for help here.

My worker class is below - you'll see that currently it just calls the JSON serialization and deserialization directly... and obviously that would have to change. Don't worry too much about what it does - it's tricky reflection stuff - the key thing is making it possible to serialize and deserialize with XML as well as JSON in this class using this concept of "injecting an interface".

namespace XXXXXXXXXXXX
{
    public interface IRecordSearchClientAdapter
    {
        string CallCorrectMethod(ClientServiceTypes component, string method, string request, Type[] paramTypes);
}

public class RecordSearchClientAdapter : IRecordSearchClientAdapter
{
    private IDictionary<ClientServiceTypes, object> componentMappings;

    public static IRecordSearchClientAdapter Create(IDictionary<ClientServiceTypes, object> clients)
    {
        return new RecordSearchClientAdapter(clients);
    }

    private RecordSearchClientAdapter(IDictionary<ClientServiceTypes, object> clients)
    {
        componentMappings = clients;
    }
    public string CallCorrectMethod(ClientServiceTypes component, string method, string request, Type[] paramTypes)
    {
        dynamic parsedrequest = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(request);
        //use another method to decide if it's JSON or XML, don't worry about injecting a Decorator:Interface?
        //dynamic parsedrequest = DeserializeObject(request);
        return CallCorrectMethod(component, method, parsedrequest, paramTypes);
    }

    //In this method, check for XML or JSON - then forward to the appropriate method.
    private string DeserializeObject(string request)
    {
        //stub - fixme!
        return null;
    }

    private string CallCorrectMethod(ClientServiceTypes component, string method, JObject request, Type[] paramTypes)
    {
        object client = componentMappings[component];

        MethodInfo mi = FindExactMethod(client, method, request, paramTypes);

        string response = null;

        if (paramTypes.Length == 1) // just one "request" object
        {
            var obj = DeserializeGenericObject(request, paramTypes[0]);
            var methodResponse = mi.Invoke(client, new object[] { obj });
            response = Newtonsoft.Json.JsonConvert.SerializeObject(methodResponse);
        }
        else // multiple parameters, need to grab them from the request
        {
            JEnumerable<JToken> tokens = request.Children();
            IEnumerator<JToken> tokenEnumerator = tokens.GetEnumerator();
            List<object> args = new List<object>();
            foreach (Type t in paramTypes)
            {
                if (!tokenEnumerator.MoveNext())
                {
                    throw new ArgumentException("Number of arguments in request doesn't match number of arguments in method");
                }

                args.Add(DeserializeGenericObject(tokenEnumerator.Current.First, t));
            }
            var methodResponse = mi.Invoke(client, args.ToArray());
            response = Newtonsoft.Json.JsonConvert.SerializeObject(methodResponse);
        }

        return response;
    }

    private MethodInfo FindExactMethod(object client, string method, JObject request, Type[] paramTypes)
    {
        // get the method that matches the name and type params
        MethodInfo mi = client.GetType().GetMethod(method, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance, null, paramTypes, null);
        return mi;
    }

    private object DeserializeGenericObject(JToken token, Type objectType)
    {
        Type myClassType = this.GetType();
        MethodInfo methodToCall = myClassType.GetMethod("DeserializeGenericTemplate", BindingFlags.IgnoreCase | BindingFlags.NonPublic | BindingFlags.Instance);
        MethodInfo genericMethodToCall = methodToCall.MakeGenericMethod(new Type[] { objectType });
        object newObject = genericMethodToCall.Invoke(this, new[] { token });

        return newObject;
    }

    private T DeserializeGenericTemplate<T>(JToken token)
    {
        T obj = token.ToObject<T>();
        return obj;
    }
}

}

解决方案

Not sure why you need this in ONE class. Your design seems like an overkill. I would have an interface to define common behavior (serialize and deserialize) and two implementation classes, one for JSON and another for XML, something like this

public interface ISerialize<T>
{
    T Deserialize<T>(string input);
    string Serialize(T type)
}

public class JsonSerializer<T> : ISerialize<T>
{
    T Deserialize<T>(string input) {...}
    string Serialize(T type) {...}
}

public class XmlSerializer<T> : ISerialize<T>
{
    T Deserialize<T>(string input) {...}
    string Serialize(T type) {...}
}

And here is how I would use it

public class Foo<T>
{
    private ISerializer<T> _serialiser;

    public Foo<T>(ISerializer<T> serialiser)
    {
        _serialiser = serialiser;
    }

    void DoFoo()
    {
        string result = serialiser.Serialize(instanceOfA_1);
        var instanceOfA_2 = serialiser.Deserialize<ClassA>(result);
    }
}

If you don't know which serializer is required - use an interface, for example, by injecting it into a constructor.

这篇关于使用设计模式在C#中为类添加功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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