创建示例项目

This commit is contained in:
sanchime 2023-04-07 22:10:35 +08:00
commit bd0c9bbf4a
20 changed files with 671 additions and 0 deletions

35
.gitignore vendored Normal file
View File

@ -0,0 +1,35 @@
# 编译目录
bin/
obj/
.idea/
.vscode/
.vs/
# Nuget包目录
packages/
# 编译结果
[Dd]ebug/
[Rr]elease/
x64/
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.log
*.vspscc
*.vssscc
.builds
.fake

22
ChipDemo.sln Normal file
View File

@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", "{E6270F58-996E-4DC2-8E18-34ECF4E222AB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{09918FD7-8BF2-4DAF-BAB9-1C97E04E458B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E6270F58-996E-4DC2-8E18-34ECF4E222AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E6270F58-996E-4DC2-8E18-34ECF4E222AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E6270F58-996E-4DC2-8E18-34ECF4E222AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E6270F58-996E-4DC2-8E18-34ECF4E222AB}.Release|Any CPU.Build.0 = Release|Any CPU
{09918FD7-8BF2-4DAF-BAB9-1C97E04E458B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{09918FD7-8BF2-4DAF-BAB9-1C97E04E458B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{09918FD7-8BF2-4DAF-BAB9-1C97E04E458B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{09918FD7-8BF2-4DAF-BAB9-1C97E04E458B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

14
Core/Core.csproj Normal file
View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>Demo</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Folder Include="Extensions" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,38 @@
using Demo.Models;
namespace Demo.Features;
/// <summary>
/// 默认的功能类,做委托容器用
/// </summary>
/// <typeparam name="TMetadata"></typeparam>
public sealed class DefaultFeature<TMetadata> : Feature<TMetadata>
where TMetadata : IMetadata
{
public DefaultFeature(string name, FeatureFunction<TMetadata>? executeFunction = null,
FeatureFunctionAsync<TMetadata>? executeFunctionAsync = null,
int order = 1)
{
_executeFunction = executeFunction;
_executeFunctionAsync = executeFunctionAsync;
Name = name;
Order = order;
}
private readonly FeatureFunction<TMetadata>? _executeFunction;
private readonly FeatureFunctionAsync<TMetadata>? _executeFunctionAsync;
public override void Execute(TMetadata metadata)
{
_executeFunction?.Invoke(this, metadata);
}
public override async ValueTask ExecuteAsync(TMetadata metadata)
{
if (_executeFunctionAsync is not null)
{
await _executeFunctionAsync.Invoke(this, metadata);
}
}
}

43
Core/Features/Feature.cs Normal file
View File

@ -0,0 +1,43 @@
using Demo.Models;
namespace Demo.Features;
/// <summary>
/// 抽象功能类
/// </summary>
public abstract class Feature<TMetadata>
where TMetadata : IMetadata
{
/// <summary>
/// 执行顺序
/// </summary>
public int Order { get; init; }
public bool Finished { get; protected set; }
public string Name { get; init; } = String.Empty;
public abstract void Execute(TMetadata metadata);
public virtual ValueTask ExecuteAsync(TMetadata metadata)
{
Execute(metadata);
return ValueTask.CompletedTask;
}
public virtual void OnException(FeatureExceptionContext<TMetadata> context)
{
throw context.Exception;
}
public virtual ValueTask OnExceptionAsync(FeatureExceptionContext<TMetadata> context)
{
throw context.Exception;
}
}
public delegate void FeatureFunction<TMetadata>(Feature<TMetadata> feature, TMetadata metadata)
where TMetadata : IMetadata;
public delegate ValueTask FeatureFunctionAsync<TMetadata>(Feature<TMetadata> feature, TMetadata metadata)
where TMetadata : IMetadata;

View File

@ -0,0 +1,19 @@
using Demo.Models;
namespace Demo.Features;
public class FeatureException<TMetadata> : Exception
where TMetadata : IMetadata
{
public TMetadata Metadata { get; }
public Feature<TMetadata> Feature { get; }
private Exception _innerException;
public FeatureException(TMetadata metadata, Feature<TMetadata> feature, Exception ex) : base(ex.Message)
{
Metadata = metadata;
Feature = feature;
_innerException = ex;
}
}

View File

@ -0,0 +1,23 @@
using Demo.Models;
namespace Demo.Features;
/// <summary>
/// 功能运行时异常上下文
/// </summary>
public class FeatureExceptionContext<TMetadata>
where TMetadata : IMetadata
{
public Feature<TMetadata> Feature { get; }
public FeatureException<TMetadata> Exception { get; }
public FeatureExceptionContext(Feature<TMetadata> feature, FeatureException<TMetadata> exception)
{
Feature = feature;
Exception = exception;
}
/// <summary>
/// 表示异常是否已处理
/// </summary>
public bool Handled { get; set; } = false;
}

View File

@ -0,0 +1,17 @@
using System.Collections.ObjectModel;
using Demo.Models;
namespace Demo.Features;
/// <summary>
/// 功能列表容器
/// </summary>
/// <typeparam name="TMetadata"></typeparam>
public class FeatureList<TMetadata> : Dictionary<string, Feature<TMetadata>>
where TMetadata : IMetadata
{
public FeatureList(IDictionary<string, Feature<TMetadata>>? list = null)
: base(list ?? new Dictionary<string, Feature<TMetadata>>())
{
}
}

View File

@ -0,0 +1,144 @@
using System.ComponentModel.Design;
using Demo.Models;
namespace Demo.Features;
public class FeatureWrapper<TMetadata>
where TMetadata : IMetadata
{
private readonly TMetadata _metadata;
protected FeatureList<TMetadata> Features { get; }
public FeatureWrapper(TMetadata metadata, FeatureList<TMetadata>? features = null)
{
_metadata = metadata;
Features = features ?? new FeatureList<TMetadata>();
}
public FeatureWrapper<TMetadata> DropFeature(string name)
{
if (String.IsNullOrWhiteSpace(name))
{
throw new CheckoutException("功能名称不能为空或空白字符");
}
Features.Remove(name);
return this;
}
/// <summary>
/// 添加功能
/// </summary>
/// <param name="feature"></param>
/// <typeparam name="TFeature"></typeparam>
/// <returns></returns>
public FeatureWrapper<TMetadata> WithFeature<TFeature>(TFeature feature)
where TFeature : Feature<TMetadata>
{
if (feature is null)
{
return this;
}
if (String.IsNullOrWhiteSpace(feature.Name))
{
throw new CheckoutException("功能名称不能为空或空白字符");
}
Features.TryAdd(feature.Name, feature);
return this;
}
/// <summary>
/// 添加功能
/// </summary>
/// <param name="name"></param>
/// <param name="feature"></param>
/// <param name="order"></param>
/// <returns></returns>
public FeatureWrapper<TMetadata> WithFeature(string name, FeatureFunction<TMetadata> feature, int order = 1)
{
if (String.IsNullOrWhiteSpace(name))
{
throw new CheckoutException("功能名称不能为空或空白字符");
}
if (feature is not null)
{
Features.TryAdd(name, new DefaultFeature<TMetadata>(name, feature, order: order));
}
return this;
}
/// <summary>
/// 添加功能
/// </summary>
/// <param name="name"></param>
/// <param name="feature"></param>
/// <param name="order"></param>
/// <returns></returns>
public FeatureWrapper<TMetadata> WithFeature(string name, FeatureFunctionAsync<TMetadata> feature, int order = 1)
{
if (String.IsNullOrWhiteSpace(name))
{
throw new CheckoutException("功能名称不能为空或空白字符");
}
if (feature is not null)
{
Features.TryAdd(name, new DefaultFeature<TMetadata>(name, executeFunctionAsync: feature, order: order));
}
return this;
}
public void Execute()
{
foreach (var feature in Features.Values.OrderBy(f => f.Order))
{
try
{
feature.Execute(_metadata);
if (feature.Finished)
{
break;
}
}
catch (Exception ex)
{
feature.OnException(new FeatureExceptionContext<TMetadata>(feature, new FeatureException<TMetadata>(_metadata, feature, ex)));
}
}
}
public void Execute(string name)
{
if (Features.TryGetValue(name, out var feature))
{
feature.Execute(_metadata);
}
else
{
throw new KeyNotFoundException(name);
}
}
public async ValueTask ExecuteAsync()
{
foreach (var feature in Features.Values.OrderBy(f => f.Order))
{
try
{
await feature.ExecuteAsync(_metadata);
if (feature.Finished)
{
break;
}
}
catch (Exception ex)
{
await feature.OnExceptionAsync(new FeatureExceptionContext<TMetadata>(feature, new FeatureException<TMetadata>(_metadata, feature, ex)));
}
}
}
}

67
Core/Models/Chip.cs Normal file
View File

@ -0,0 +1,67 @@
using Demo.Features;
using Demo.Primitives;
namespace Demo.Models;
public abstract class Chip : IMetadata
{
/// <summary>
/// 属性
/// </summary>
public MetadataPropertySet Properties { get; }
public string Name { get; set; }
public Version Version { get; set; } = new Version(0, 0, 0);
/// <summary>
/// 功能
/// </summary>
public virtual FeatureWrapper<Chip> Features { get; }
/// <summary>
/// 公式
/// </summary>
public FormulaExecutor Formula { get; protected set; }
protected Chip(Chip? @base = null, bool needInherit = true)
{
if (needInherit)
{
Properties = @base?.Properties ?? new MetadataPropertySet();
}
else
{
Properties = new MetadataPropertySet();
}
Features = new FeatureWrapper<Chip>(this);
Formula = new FormulaExecutor(null, null);
Initialize();
}
public MetadataPropertySet.MetadataProperty? this[string name]
{
get => Properties.GetValue(name);
set => Properties.SetValue(name, value);
}
public Chip SetProperty(string name, object? value)
{
Properties.SetValue(name, value);
return this;
}
public TValue? GetProperty<TValue>(string name)
{
return Properties.GetValue(name).Cast<TValue>();
}
/// <summary>
/// 初始化
/// </summary>
protected virtual void Initialize()
{
// var properties = this.GetType().GetProperties();
}
}

12
Core/Models/Formula.cs Normal file
View File

@ -0,0 +1,12 @@
namespace Demo.Models;
/// <summary>
/// 公式模型类
/// </summary>
public class Formula
{
/// <summary>
/// 是否启用
/// </summary>
public bool Enabled { get; set; } = true;
}

View File

@ -0,0 +1,6 @@
namespace Demo.Models;
public class FormulaExecutionContext
{
}

14
Core/Models/IMetadata.cs Normal file
View File

@ -0,0 +1,14 @@
using Demo.Features;
namespace Demo.Models;
/// <summary>
/// 元数据
/// </summary>
public interface IMetadata
{
/// <summary>
/// 属性
/// </summary>
MetadataPropertySet Properties { get; }
}

View File

@ -0,0 +1,110 @@
using System.Collections;
using System.Collections.Concurrent;
namespace Demo.Models;
public class MetadataPropertySet : IReadOnlyDictionary<string, MetadataPropertySet.MetadataProperty>
{
private readonly IDictionary<string, MetadataProperty> _properties;
public MetadataPropertySet()
{
_properties = new Dictionary<string, MetadataProperty>();
}
public bool ContainsKey(string key)
{
return _properties.ContainsKey(key);
}
public bool TryGetValue(string key, out MetadataProperty value)
{
return _properties.TryGetValue(key, out value);
}
public IEnumerable<string> Keys => _properties.Keys;
public IEnumerable<MetadataProperty> Values => _properties.Values;
public MetadataProperty? this[string name]
{
get => GetValue(name);
}
internal void SetValue(string name, object value)
{
if (_properties.TryGetValue(name, out var property))
{
property.Value = value;
}
else
{
property = new MetadataProperty(name, value);
_properties.TryAdd(name, property);
}
}
internal MetadataProperty? GetValue(string name)
{
if (_properties.TryGetValue(name, out var property))
{
return property;
}
return null;
}
public class MetadataProperty
{
public bool IsNull { get; private set; }
public Type? Type { get; private set; }
private object? _value;
/// <summary>
/// 属性值
/// </summary>
public object? Value
{
get => _value;
set
{
IsNull = value is null;
Type = value?.GetType();
_value = value;
}
}
public string Name { get; init; }
public TValue? Cast<TValue>()
{
if (typeof(TValue) == Type)
{
return (TValue)Convert.ChangeType(Value, Type);
}
return (TValue)Value;
}
public MetadataProperty(string name, object? value)
{
(Name, Value) = (name, value);
}
public override string ToString()
{
return Value?.ToString()!;
}
}
public IEnumerator<KeyValuePair<string, MetadataProperty>> GetEnumerator()
{
return _properties.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int Count => _properties.Count;
}

View File

@ -0,0 +1,21 @@
using Demo.Models;
namespace Demo.Primitives;
public class FormulaExecutor : IComputable<FormulaExecutionContext, decimal>
{
private IFormulaEngine _engine;
private FormulaExpressionParser _parser;
public FormulaExecutor(IFormulaEngine engine, FormulaExpressionParser parser)
{
_engine = engine;
_parser = parser;
}
public decimal Compute(FormulaExecutionContext context)
{
Console.WriteLine("计算过程");
return default;
}
}

View File

@ -0,0 +1,6 @@
namespace Demo.Primitives;
public class FormulaExpressionParser
{
}

View File

@ -0,0 +1,16 @@
namespace Demo.Primitives;
/// <summary>
/// 可计算单元
/// </summary>
public interface IComputable<TInput, TResult>
{
/// <summary>
/// 计算
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
TResult Compute(TInput input);
// TResult Compute(Func<TInput, TResult> computor);
}

View File

@ -0,0 +1,9 @@
namespace Demo.Primitives;
/// <summary>
/// 公式引擎
/// </summary>
public interface IFormulaEngine
{
}

14
Example/Example.csproj Normal file
View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Core\Core.csproj" />
</ItemGroup>
</Project>

41
Example/Program.cs Normal file
View File

@ -0,0 +1,41 @@
using Demo.Models;
try
{
IcndChip icndChip = new IcndChip();
icndChip.SetProperty("Code", "1234")
.SetProperty("Name", "芯片");
icndChip.Features.Execute(); // 执行所有功能
icndChip.Features
.DropFeature("场频自适应功能")
.Execute();
icndChip.Features.Execute("场频自适应功能");
icndChip.Formula.Compute(new FormulaExecutionContext() // 计算公式(需要调整)
{
});
Console.WriteLine(icndChip.GetProperty<string>("Code"));
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
public class IcndChip : Chip
{
protected override void Initialize()
{
Name = "ICND芯片";
Features.WithFeature("场频自适应功能", (f, m) =>
{
Console.WriteLine($"{m.Name}调用{f.Name}");
}).WithFeature("其他功能", (f, m) =>
{
Console.WriteLine($"{m.Name}调用{f.Name},得到属性[\"Code\"]值{m.GetProperty<string>("Code")}");
});
}
}