在 C# 中使用接口

本文关键字:接口 | 更新日期: 2023-09-27 18:21:36

我创建了一个名为UserSessionModel的类;在其中我存储了一些关于用户的数据,特别是我存储了几个json字符串,它们是查询和序列化的结果。

我在UserSessionModel中有几个方法和属性,总体上看起来像这样:

public string SomeUserDataInJson1 { get; set; }
public string SomeUserDataInJson2 { get; set; }
.... 3 more properties like this
public int UserID { get; set; }
private void GetSomeUserDataInJson1
{
   ObjectData1 TheObjectData1 = new ObjectData1();
   UserQueries TheUserQueries = new UserQueries();
   JavascriptSerializer TheSerializer = new JavascriptSerializer();
   TheObjectData1 = TheUserQueries.GetData1(TheUserID);
   this.SomeUserData1InJson = TheSerializer.Serialize(TheObjectData1);
}

此代码重复 5 次,唯一的更改是 ObjectData、查询名称和要设置的属性 SomeUserData。

有没有办法用接口或其他一些 c# 工具让它"更好"?

谢谢。

在 C# 中使用接口

好的,让我们假设您的示例如下:您正在使用每个用户 (userId( 定义不同的查询进行处理的数据。

我们的数据容器类在这里非常简单,只包含一个字符串。

public class Data
{
    public string Content { get; set; }
}

下一步,让我们看一下查询...可能正在使用该接口(可以使用事件作为响应,但让我们在这里保持简单(。

public interface IQuery
{
    Data Process(Data data);
}

您可以通过将 userId 添加到 IQuery 接口来与用户建立关系,但我更愿意使用另一个接口来解决这个问题:

public interface IUserQueryProvider
{
    IEnumerable<IQuery> GetQuerysForUser(uint id);
}

这样,您可以将用户更改为在单独的位置进行查询解析。

您还将拥有一个序列化程序/转换器。好的,让我们在这里创建一个接口来序列化(处理的(数据。

public interface ISerializer
{
    string Serialize(Data data);
}

现在,让我们看一下实现,首先是序列化程序...在这里没有做任何神奇的事情,你应该填写序列化对象所需的东西(JSON,...

public class JavascriptSerializer : ISerializer
{
    public string Serialize(Data data)
    {
        return data.Content; //whatever you want do instead for serialization
    }
}

现在让我们转到我们的查询。我假设你对设计模式不是很熟悉,你的意思是命令模式之类的东西(对于处理作业,请参阅我在评论中的链接以获取有关设计模式的更多信息(。下面有 3 个实现作为示例:

public class ReplaceQuery : IQuery
{
    private readonly string match;
    private readonly string text;
    public ReplaceQuery(string match, string text)
    {
        this.match = match;
        this.text = text;
    }
    public Data Process(Data data)
    {
        return data.Content.Contains(match) ? new Data {Content = data.Content.Replace(match, text)} : null;
    }
}
public class GreetingToQuery : IQuery
{
    private readonly string greeting;
    private readonly string place;
    public GreetingToQuery(string greeting, string place)
    {
        this.greeting = greeting;
        this.place = place;
    }
    public Data Process(Data data)
    {
        return data.Content.Contains(greeting) ? new Data {Content = data.Content + place + "."} : null;
    }
}
public class LineEndingQuery : IQuery
{
    public Data Process(Data data)
    {
        return data.Content.LastIndexOf(".", StringComparison.Ordinal) == data.Content.Length - 1 &&
               data.Content.Length > 0
                   ? new Data {Content = "'n"}
                   : null;
    }
}

如果我们想解析哪些查询属于用户,我们需要我们的IUserQueryProvider实现。在这种情况下,它只不过是一个字典(但可以很容易地切换到其他实现(。

public class SampleQueryProvider : Dictionary<uint, IEnumerable<IQuery>>, IUserQueryProvider
{
    public IEnumerable<IQuery> GetQuerysForUser(uint id)
    {
        IEnumerable<IQuery> queries;
        TryGetValue(id, out queries);
        return queries;
    }
}

最后但同样重要的。。。一切的粘合剂。我在这里为我们的"发电机引擎"添加了另一个接口。

public interface IScriptGenerator
{
    event Action<string> Script;
    void Generate(Data data, IEnumerable<IQuery> queries);
}

为了使它更加灵活,我按照Ralf Westphal引入的设计原则制作了接口/实现,称为基于事件的组件(EBC(。如果你对这个话题感兴趣,谷歌是你的朋友。

public class SampleScriptGenerator : IScriptGenerator
{
    private readonly ISerializer serializer;
    public event Action<string> Script;
    public SampleScriptGenerator(ISerializer serializer)
    {
        this.serializer = serializer;
    }
    public void Generate(Data data, IEnumerable<IQuery> queries)
    {
        foreach (string serialized in from query in queries select query.Process(data) into result where result != null select serializer.Serialize(result))
        {
            OnSerialize(serialized);
        }
    }
    private void OnSerialize(string serialized)
    {
        var handler = Script;
        if (handler != null) handler(serialized);
    }
}

现在让我们把它们放在一起,让我们飞翔:

    static void Main()
    {
        var generator = new SampleScriptGenerator(new JavascriptSerializer());
        generator.Script += Console.Write; // bind to console output here
        var queryProvider = new SampleQueryProvider
                                {
                                    {
                                        1, // user with id 1
                                        new List<IQuery>
                                            {
                                                new ReplaceQuery("<name>", "frenchie"),
                                                new GreetingToQuery("bonjour", "the universe"),
                                                new LineEndingQuery()
                                            }
                                        },
                                    {
                                        2, // user with id 2
                                        new List<IQuery>
                                            {
                                                new ReplaceQuery("<name>", "stegi"),
                                                new GreetingToQuery("hello", "the world"),
                                                new LineEndingQuery()
                                            }
                                        }
                                };

        var data1 = new Data {Content = "My name is <name>."};
        var data2 = new Data {Content = "I say hello to "};
        var data3 = new Data {Content = "I say bonjour to "};
        var data4 = new Data {Content = "."};

        // you cold combine data and user query execution into lists and loops, too
        generator.Generate(data1, queryProvider.GetQuerysForUser(1));
        generator.Generate(data2, queryProvider.GetQuerysForUser(1));
        generator.Generate(data3, queryProvider.GetQuerysForUser(1));
        generator.Generate(data4, queryProvider.GetQuerysForUser(1));
        generator.Generate(data1, queryProvider.GetQuerysForUser(2));
        generator.Generate(data2, queryProvider.GetQuerysForUser(2));
        generator.Generate(data3, queryProvider.GetQuerysForUser(2));
        generator.Generate(data4, queryProvider.GetQuerysForUser(2));
        Console.ReadKey();
    }
}

您应该看到类似以下内容:

My name is frenchie.
I say bonjour to the universe.
My name is stegi.
I say hello to the world.

作为你的家庭作业...尝试添加自己的查询实现和要处理的数据。您将如何在此处添加递归?;-)

首先,

您绝对应该使用List<string>string[]。然后,您可以增加代码空间和可扩展性。您可以像在那里一样循环访问数据并将其加载到列表中。另一件事,你的意思是TheQueries TheUserQueries,因为我看不到后者声明或使用前者。

如果您发现自己像以前一样创建了两个以上的类似属性,则可能应该使用 List

其次,接口的要点是强制对象实现某些方法等,然后可以在其他类中调用和访问这些方法。如果这对您有帮助,那么您可以将您的方法放在界面中。否则真的没有意义。