在 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# 工具让它"更好"?
谢谢。
好的,让我们假设您的示例如下:您正在使用每个用户 (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
。
其次,接口的要点是强制对象实现某些方法等,然后可以在其他类中调用和访问这些方法。如果这对您有帮助,那么您可以将您的方法放在界面中。否则真的没有意义。