8

F#には、「with」という便利な機能があります。例:

type Product = { Name:string; Price:int };;
let p = { Name="Test"; Price=42; };;
let p2 = { p with Name="Test2" };;

レコードタイプはデフォルトで不変であるため、F#はキーワード「with」を作成しました。

さて、C#で同様の拡張機能を定義することは可能ですか?C#のように、文字列を変換する方法がわからないので、少し注意が必要なようです

Name="Test2"

代表者または表現に?

4

4 に答える 4

4
public static T With<T, U>(this T obj, Expression<Func<T, U>> property, U value)
    where T : ICloneable {
    if (obj == null)
        throw new ArgumentNullException("obj");
    if (property == null)
        throw new ArgumentNullException("property");
    var memExpr = property.Body as MemberExpression;
    if (memExpr == null || !(memExpr.Member is PropertyInfo))
        throw new ArgumentException("Must refer to a property", "property");
    var copy = (T)obj.Clone();
    var propInfo = (PropertyInfo)memExpr.Member;
    propInfo.SetValue(copy, value, null);
    return copy;
}

public class Foo : ICloneable {
    public int Id { get; set; } 
    public string Bar { get; set; }
    object ICloneable.Clone() {
        return new Foo { Id = this.Id, Bar = this.Bar };
    }
}

public static void Test() {
    var foo = new Foo { Id = 1, Bar = "blah" };
    var newFoo = foo.With(x => x.Bar, "boo-ya");
    Console.WriteLine(newFoo.Bar); //boo-ya
}

または、コピーコンストラクターを使用します。

public class Foo {
    public Foo(Foo other) {
        this.Id = other.Id;
        this.Bar = other.Bar;
    }
    public Foo() { }
    public int Id { get; set; } 
    public string Bar { get; set; }
}

public static void Test() {
    var foo = new Foo { Id = 1, Bar = "blah" };
    var newFoo = new Foo(foo) { Bar = "boo-ya" };
    Console.WriteLine(newFoo.Bar);
}

そして、ジョージの優れた提案のわずかなバリエーションで、複数の割り当てが可能です。

public static T With<T>(this T obj, params Action<T>[] assignments)
    where T : ICloneable {
    if (obj == null)
        throw new ArgumentNullException("obj");
    if (assignments == null)
        throw new ArgumentNullException("assignments");
    var copy = (T)obj.Clone();
    foreach (var a in assignments) {
        a(copy);
    }
    return copy;
}

public static void Test() {
    var foo = new Foo { Id = 1, Bar = "blah" };
    var newFoo = foo.With(x => x.Id = 2, x => x.Bar = "boo-ya");
    Console.WriteLine(newFoo.Bar);
}

(1)汎用ソリューションは不必要に遅く、複雑になるため、おそらく2番目のソリューションを使用します。(2)それはあなたが望むものに最も近い構文を持っています(そして構文はあなたが期待することをします); (3)F#のコピーと更新の式も同様に実装されます。

于 2011-07-26T16:03:56.880 に答える
2

多分このようなもの:

void Main()
{
    var NewProduct = ExistingProduct.With(P => P.Name = "Test2");
}

// Define other methods and classes here

public static class Extensions
{
    public T With<T>(this T Instance, Action<T> Act) where T : ICloneable
    {
        var Result = Instance.Clone();
        Act(Result);

        return Result;
    }
}
于 2011-07-26T16:00:15.980 に答える
0

ラムダ関数の代わりに、デフォルト値のパラメーターを使用できます。唯一の小さな問題は、このパラメーターを変更しないことを意味するデフォルト値を選択する必要があることです(参照型の場合)nullが、安全な選択である必要があります。

class Product {
   public string Name { get; private set; }
   public int Price { get; private set; }
   public Product(string name, int price) {
     Name = name; Price = price;
   }

   // Creates a new product using the current values and changing
   // the values of the specified arguments to a new value
   public Product With(string name = null, int? price = null) {
     return new Product(name ?? Name, price ?? Price);
   }
 }

 // Then you can write:
 var prod2 = prod1.With(name = "New product");

メソッドを自分で定義する必要がありますが、常にそうです(リフレクションを使用する場合を除いて、効率は低くなります)。構文もかなりいいと思います。F#のように見栄えを良くしたい場合は、F#を使用する必要があります:-)

于 2011-07-26T16:24:47.373 に答える
0

There is no native ability to do this in C# short of an extension method, but at what cost? a and b are reference types and any suggestion that b is based ("with") on a causes immediate confusion as to how many objects we are working with. Is there only one? Is b a copy of a ? Does b point to a ?

C# is not F#.

Please see a previous SO question of mine as answered by Eric Lippert:

"Amongst my rules of thumb for writing clear code is: put all side effects in statements; non-statement expressions should have no side effects."

More fluent C# / .NET

于 2011-07-26T16:37:19.673 に答える