0

C# で次のことを達成するエレガントな (または任意の) 方法はありますか?

  • ユーザーが の「追跡されていない」インスタンスを作成するのを防ぐために、直接インスタンス化 (非公開の構築) を許可しないクラスItemBase(さらに に派生可能) を用意しましょう。Item1Item2Item*
  • Managerインスタンス (複数のインスタンスを許可)のみを作成および提供できる非静的クラスを用意しますItem*(生成されたインスタンスを追跡し、追加の作業を行うため)。
  • オプションの要件があります。Managerインスタンスは、マネージド インスタンスの非パブリック メンバーを操作したいと考えています ( が ofになるのとItem同様です)。ManagerfriendItem*
  • Managerが の派生であることを強要されなければいいのですがItem*
  • 反射が少ないのがいいですね。

ノート:

  • 可能であれば、これを、特定の問題の解決策を最善かつエレガントな方法で実装する方法を考えるプロセスから生じる質問と考えてください。いいえ、ソースはありません。はい、すでにいくつかのバリエーションを試しましたが、どれも私のニーズを満たしていませんでした。ありがとうございました。

  • 私の知る限り、受け入れられるfriend代替手段はありません (どれでも良いinternalInternalsVisibleToAttribute思われます)。そのため、ItemBase「特別な」(しかし公開されている) 変更メソッドを提供するだけであり、ユーザーはこれらのメソッドがユーザー向けではないことに注意する必要があります:o (

  • 私はこのソリューションが好きですが、それを使用して複数のManagerインスタンスを許可する方法を発明することはできません。

4

2 に答える 2

0

これで問題が解決すると思います:

public class ItemBase

{
    protected ItemBase()
    {

    }
    public void PublicMethod() { }
    public int PublicProperty { get; set; }
}

public class Factory
{
    private class PrivateItemBase : ItemBase
    {
        public void PrivateMethod() { }
        public int PrivateProperty { get; set; }
    }

    public Factory(int id)
    {

    }

    public IEnumerable<ItemBase> Items { get; private set; }
    public ItemBase CreateItem()
    {
        PrivateItemBase rValue = new PrivateItemBase();

        rValue.PrivateMethod();
        rValue.PrivateProperty = 4;

        return rValue;
    }
}
于 2015-09-11T15:00:18.723 に答える
0

わかりました、あきらめます。これが目的を完全に理解するのに役立つ場合は、私が(現在)最終的に得た、それほど悪くない解決策があります。作成関数の受け渡しは、静的コンストラクター (ユーザーはアクセスできません) を介して行われますが、残念ながら、その呼び出しは醜いものです...

それを改善する方法はありますか?

アイテムの定義:

namespace SpecialFactory
{
    public enum ItemType
    {
        Item1,
        Item2,
        // ... Anyone deriving the Item* should add an item here
    }

    public abstract class ItemBase
    {
        public abstract ItemType Id {get;}

        public static void RegisterAllCreators()
        {
            // Force static constructors invocation
            var it = Item1.ClassId | Item2.ClassId; // Anyone deriving the Item* should ensure invocation of Manager.RegisterCreator
        }
    }

    public class Item1 : ItemBase
    {
        static Item1()
        {
            Manager.RegisterCreator(ItemType.Item1, () => new Item1());
        }

        protected Item1()
        {
        }

        public static   ItemType ClassId => ItemType.Item1;
        public override ItemType Id      => ClassId;
    }

    public class Item2 : ItemBase
    {
        static Item2()
        {
            Manager.RegisterCreator(ItemType.Item2, () => new Item2());
        }

        protected Item2()
        {
        }

        public static   ItemType ClassId => ItemType.Item2;
        public override ItemType Id      => ClassId;
    }
}

マネージャー:

namespace SpecialFactory
{
    public class Manager
    {
        static Manager()
        {
            ItemBase.RegisterAllCreators();
        }

        protected static Dictionary<ItemType, Func<ItemBase>> creators = new Dictionary<ItemType, Func<ItemBase>>();
        protected readonly List<ItemBase> managedItems = new List<ItemBase>();

        protected ItemBase CreateItem(ItemType type)
        {
            ItemBase item = null;

            if (creators.ContainsKey(type))
            {
                if ((item = creators[type]()) != null)
                    managedItems.Add(item);
            }

            return item;    
        }

        public static void RegisterCreator(ItemType type, Func<ItemBase> creator)
        {
            if (!creators.ContainsKey(type))
                creators[type] = creator;
        }

        public Manager()
        {

        }

        public ItemBase Test(ItemType type)
        {
            // var notAllowed = new Item1();
            var allowed = CreateItem(type);

            return allowed;
        }
    }
}

テスト:

namespace SpecialFactory
{
    class Program
    {
        static void Main(string[] args)
        {
            var m1 = new Manager();
            var m2 = new Manager();

            var i1 = m1.Test(ItemType.Item1);
            var i2 = m2.Test(ItemType.Item2);
        }
    }
}
于 2015-09-11T15:36:26.483 に答える