ダックタイピングとC#

良い一日。私は最近、.Net5とそのソースジェネレーターで多くの実験を行っています。そして、私は突然、ソースジェネレータを使用してC#で「ダックタイピング」を実装する方法を思いつきました。この考えをそのままにしておくことはできませんでした。その結果、純粋にアカミックなものが出てきたと思いますが(これを本番環境で使用する人はいないと思います)、結果は非常に興味深いものです。カットを求めることに興味がある人は誰でも!







ネタバレ

実装自体については詳しく説明しません。リポジトリで表示できます。リンクは以下にあります。すでにジェネレーターに手を出している人にとっては難しいことではありませんが、他のすべての人にとっては、はるかに大きな記事が必要です。







それの使い方



次の例があると想像してみましょう。







public interface ICalculator
{
  float Calculate(float a, float b);
}

public class AddCalculator
{

  float Calculate(float a, float b);
}
      
      





AddCalculator



いかなる方法でも実装されないことに注意することが重要ICalculator



です。

それらは同一の署名しか持っていません。次のように使用しようとすると、失敗します。







var addCalculator = new AddCalculator();

var result = Do(addCalculator, 10, 20);

float Do(ICalculator calculator, float a, float b)
{
  return calculator.Calculate(a, b);
}

      
      





C#コンパイラは次のように言います。







Argument type 'AddCalculator' is not assignable to parameter type 'ICalculator'









そして彼は正しいでしょう。しかし、署名はAddCalculator



完全に同じでICalculator



あり、本当にこれを実行したいので、解決策はC#では機能しないダックタイピングである可能性があります。これは、nugetパッケージが役立つところDuckInterface



です。あなたがする必要があるのはそれをインストールし、私たちの署名を少し微調整することです。インターフェイスに属性を追加して、インターフェイスから始めましょうDuckable









[Duckable]
public interface ICalculator
{
  float Calculate(float a, float b);
}
      
      





Do



. ICalculator



DICalculator



. DICalculator



DuckInterface



.

DICalculator



ICalculator



. IDE. DICalculator



.







:







var addCalculator = new AddCalculator();

var result = Do(addCalculator, 10, 20);

float Do(DICalculator calculator, float a, float b)
{
  return calculator.Calculate(a, b);
}

      
      





. .









. Duckable



"" . , ICalculator



:







public partial class DICalculator : ICalculator 
{
  [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] 
  private readonly Func<float, float, float> _Calculate;        

  [System.Diagnostics.DebuggerStepThrough]
  public float Calculate(float a, float b)
  {
      return _Calculate(a, b);
  }
}
      
      





duckable . :







var result = Do(addCalculator, 10, 20);
      
      





Do



DICalculator



, addCalculator



. , DICalculator



:







public partial class DICalculator
{
  private DICalculator(global::AddCalculator value) 
  {
       _Calculate = value.Calculate;
  }

  public static implicit operator DICalculator(global::AddCalculator value)
  {
      return new DICalculator(value);
  }
}
      
      





DICalculator



partial class . , :







:







[Duckable]
public interface ICalculator
{
    float Zero { get; }
    float Value { get; set; }
    float Calculate(float a, float b);
}
// ....
public partial class DICalculator : ICalculator 
{
    [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] 
    private readonly Func<float> _ZeroGetter;

    [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] 
    private readonly Func<float> _ValueGetter;

    [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] 
    private readonly Action<float> _ValueSetter;

    [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] 
    private readonly Func<float, float, float> _Calculate;        

    public float Zero
    {
         [System.Diagnostics.DebuggerStepThrough] get { return _ZeroGetter(); }
    }

    public float Value
    {
         [System.Diagnostics.DebuggerStepThrough] get { return _ValueGetter(); }
         [System.Diagnostics.DebuggerStepThrough] set { _ValueSetter(value); }
    }

    [System.Diagnostics.DebuggerStepThrough]
    public float Calculate(float a, float b)
    {
        return _Calculate(a, b);
    }
}
      
      







. - duck typing . . ref struct-. , . , where - :







float Do<TCalcualtor>(TCalcualtor calculator, float a, float b)
    where TCalcualtor: DICalculator
{
  return calculator.Calculate(a, b);
}
      
      





zero cost duct typing( , ), , partial class



partial struct



duck . , Do



TCalcualtor



. , , .

. !







Nuget here

Github here








All Articles