Commit bc672709 authored by shrabbit's avatar shrabbit
Browse files

初始化项目结构,添加节点转换器和图相关类,更新上下文和属性接口

parent 8662108c
Loading
Loading
Loading
Loading
+120 −0
Original line number Diff line number Diff line
using System.Collections;
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;

namespace Nocube.Common;

/// <summary>
/// 公共上下文,继承 GUID 对 Object 的字典。
/// </summary>
public class CommonContext : ConcurrentDictionary<Guid, object>
{
    /// <summary>
    /// 获取第一个与类型匹配的实例
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public T GetFirst<T>()
    {
        return Values.OfType<T>().FirstOrDefault()!;
    }

    /// <summary>
    /// 获取所有与类型匹配的实例
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public IEnumerable<T> Get<T>()
    {
        return Values.OfType<T>();
    }

    /// <summary>
    /// 添加一个类型
    /// </summary>
    /// <param name="guid">用于索引实例的 GUID。</param>
    /// <param name="obj">待加入的实例</param>
    /// <typeparam name="T">无约束</typeparam>
    /// <returns>如果加入成功,返回true,否则为false。</returns>
    public bool Add<T>(Guid guid, T obj)
    {
        return TryAdd(guid, obj);
    }

    /// <summary>
    /// 添加一个类型
    /// </summary>
    /// <typeparam name="T">允许无参构造</typeparam>
    /// <returns>能够直接索引这个实例的 Guid。如果添加失败,返回null。</returns>
    public Guid? Add<T>()
        where T : new()
    {
        var guid = Guid.NewGuid();
        var o = Add<T>(guid, new T());
        
        return o ? guid : null;
    }

    /// <summary>
    /// 根据 GUID 获取实例
    /// </summary>
    /// <param name="guid">GUID 索引</param>
    /// <typeparam name="T">无泛型约束</typeparam>
    /// <returns>当前实例</returns>
    public T? Get<T>(Guid guid)
    {
        TryGetValue(guid, out var obj);
        return (T?)obj;
    }
}

/// <summary>
/// 上下文构建器,用于创建固定的实例
/// </summary>
public class CommonContextBuilder
{
    private readonly CommonContext _context = [];

    public CommonContext Build() => _context;

    public CommonContextBuilder AddVersion(IVersions ver)
    {
        _context.Add(BaseContextValue.EngineVersion, ver);
        return this;
    }
}

/// <summary>
/// 上下文扩展,提供固定值的访问。
/// </summary>
/// <remarks>
/// 要求 LangVersion >= 14
/// </remarks>
public static class CommonContextExtensions
{
    extension(CommonContext context)
    {
        public Version EngineVersion => context.Get<Version>(BaseContextValue.EngineVersion);
        public Version UIVersion => context.Get<Version>(BaseContextValue.UIVersion);
        public Version Console => context.Get<Version>(BaseContextValue.Console);
        public Version Logger => context.Get<Version>(BaseContextValue.Logger);
    }
}

/// <summary>
/// 提供固定的上下文 GUID 访问。
/// </summary>
public static class BaseContextValue
{
    public static readonly Guid EngineVersion = 
        new ("{B3CB038F-7EA6-4C55-B5DC-49D758EA1732}");
    
    public static readonly Guid UIVersion = 
        new ("{DDEAE2A7-6AAC-45D2-9941-6214AB8ED822}");
    
    public static readonly Guid Console = 
        new ("{4E68E0A6-833C-45FB-9A50-396C0B34F400}");
    
    public static readonly Guid Logger = 
        new ("{A6B5AA02-1CA6-4AE9-A8D7-09A1715B0977}");
}
 No newline at end of file
+2 −0
Original line number Diff line number Diff line
@@ -4,4 +4,6 @@ public enum FlowDirect
{
    In,
    Out,
    Any,
    None
}
 No newline at end of file
+10 −0
Original line number Diff line number Diff line
namespace Nocube.Common;

public interface IVersions
{
    Version EngineVersion { get; }
    Version CommonVersion { get; }

    // ReSharper disable once InconsistentNaming
    Version UIVersion { get; }
}
 No newline at end of file
+10 −0
Original line number Diff line number Diff line
<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFramework>net10.0</TargetFramework>
        <LangVersion>14</LangVersion>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
    </PropertyGroup>

</Project>
+92 −0
Original line number Diff line number Diff line
using Nocube.Common.Properties;

namespace Nocube.Common.Nodes;

public abstract class ConverterBase<TIn, TOut> : Function, IConverter
{
    private readonly bool _twoWay;
    public Type InputType { get; } = typeof(TIn);
    public Type OutputType { get; } = typeof(TOut);
    public abstract bool IsTwoWay { get; }

    private readonly Property<TIn> _in;
    private readonly Property<TOut> _out;
    
    private readonly Property<TOut>? _inBack;
    private readonly Property<TIn>? _outBack;

    public ConverterBase(bool twoWay)
    {
        _twoWay = twoWay;
        _in = AddToProperties(new Property<TIn>(
            "Input",
            "输入数据,将转换为输出的类型。",
            FlowDirect.In
        ));

        _out = AddToProperties(new Property<TOut>(
            "Output",
            "输出数据,这是转换结果。",
            FlowDirect.Out
        ));

        if (!twoWay)
            return;

        _inBack = AddToProperties(new Property<TOut>(
            "Input (Reverse)",
            "输入数据,将转换为输出的类型(反向转换)。",
            FlowDirect.In
        ));

        _outBack = AddToProperties(new Property<TIn>(
            "Output (Reverse)",
            "输出数据,这是转换结果(反向转换)。",
            FlowDirect.Out
        ));
    }
    
    /// <summary>
    /// 数据转换,从 In 到 Out
    /// </summary>
    /// <param name="input">输入</param>
    /// <returns>输出</returns>
    public abstract TOut? Convert(TIn? input);

    /// <summary>
    /// 数据转换,从 Out 到 In
    /// </summary>
    /// <param name="input">输入</param>
    /// <returns>输出</returns>
    /// <remarks>
    /// 只有 twoWay 为 true 才会调用这个。
    /// </remarks>
    public abstract TIn? ConvertBack(TOut? input);

    public override Task Execute(CancellationToken cancellationToken = default)
    {
        // 判断输入方向,哪个In有数据。
        if (_in.Data != null)
        {
            _out.Data = Convert(_in.Data);
        }
        else
        {
            if(_twoWay && _outBack != null && _inBack != null)
                _outBack.Data = ConvertBack(_inBack.Data);
        }
        
        return Task.CompletedTask;
    }
}

public abstract class ConverterTwoWay<TIn, TOut>() : ConverterBase<TIn, TOut>(true)
{
    public override bool IsTwoWay => true;
}

public abstract class ConverterOneWay<TIn, TOut>() : ConverterBase<TIn, TOut>(false)
{
    public override bool IsTwoWay => false;
    public override TIn? ConvertBack(TOut? input) => (TIn)new object();
}
 No newline at end of file
Loading